<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[214960] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/214960">214960</a></dd>
<dt>Author</dt> <dd>clopez@igalia.com</dd>
<dt>Date</dt> <dd>2017-04-05 12:14:36 -0700 (Wed, 05 Apr 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>[WebRTC][OpenWebRTC] Add support for SDP BUNDLE (&quot;a:group:BUNDLE&quot; and &quot;a=bundle-only&quot; lines)
https://bugs.webkit.org/show_bug.cgi?id=170157

Reviewed by Alejandro G. Castro.

Source/WebCore:

This implements support on the SDPProcessor for generating an &quot;a=group:BUNDLE&quot;
attribute with the MID identifiers specified in the bundle group in the most
recent answer.
It also implements support for generating &quot;a=bundle-only&quot; attributes on the
&quot;m=&quot; sections of the SDP according to the bundlePolicy defined.

Test: fast/mediastream/RTCPeerConnection-inspect-offer-bundlePolicy-bundle-only.html

* Modules/mediastream/MediaEndpointPeerConnection.cpp:
(WebCore::MediaEndpointPeerConnection::createOfferTask):
(WebCore::MediaEndpointPeerConnection::createAnswerTask):
* Modules/mediastream/SDPProcessor.cpp:
(WebCore::getBundlePolicyName):
(WebCore::configurationToJSON):
* Modules/mediastream/sdp.js:
(SDP.generate):
* platform/mediastream/MediaEndpointSessionConfiguration.h:
(WebCore::MediaEndpointSessionConfiguration::bundlePolicy):
(WebCore::MediaEndpointSessionConfiguration::setBundlePolicy):
(WebCore::MediaEndpointSessionConfiguration::clone):

LayoutTests:

The test fast/mediastream/RTCPeerConnection-inspect-offer-bundlePolicy-bundle-only.html
is used to check that we generate the &quot;a=bundle-only&quot; lines on the &quot;m=&quot; sections
according to the bundlePolicy. The 3 possible values of bundlePolicy are tested.
To properly test bundlePolicy:&quot;balanced&quot; we generate 5 extra tracks (6 in total)
for each one of the audio media type and video media type.

* TestExpectations: Set RTCPeerConnection-inspect-offer-bundlePolicy-bundle-only.html
as failing in the general TestExpectations, because the libwebrtc backend currently
doesn't generate the expected a=bundle-only lines.
On the GTK+ port TestExpectations file this is overriden, and the test is marked to pass.
The whole fast/mediastream directory is already overriden to pass.
* fast/mediastream/RTCPeerConnection-inspect-offer-bundlePolicy-bundle-only-expected.txt: Added.
* fast/mediastream/RTCPeerConnection-inspect-offer-bundlePolicy-bundle-only.html: Added.
* fast/mediastream/resources/sdp-utils.js:
(printComparableSessionDescription): Validate the a=group:BUNDLE line to contain the required MID identifiers.
* platform/gtk/fast/mediastream/RTCPeerConnection-inspect-answer-expected.txt: Added. Rebaseline with the expected a=group:BUNDLE line.
* platform/gtk/fast/mediastream/RTCPeerConnection-inspect-offer-expected.txt: Added. Rebaseline with the expected a=group:BUNDLE line.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsTestExpectations">trunk/LayoutTests/TestExpectations</a></li>
<li><a href="#trunkLayoutTestsfastmediastreamresourcessdputilsjs">trunk/LayoutTests/fast/mediastream/resources/sdp-utils.js</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModulesmediastreamMediaEndpointPeerConnectioncpp">trunk/Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesmediastreamSDPProcessorcpp">trunk/Source/WebCore/Modules/mediastream/SDPProcessor.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesmediastreamsdpjs">trunk/Source/WebCore/Modules/mediastream/sdp.js</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreamMediaEndpointSessionConfigurationh">trunk/Source/WebCore/platform/mediastream/MediaEndpointSessionConfiguration.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastmediastreamRTCPeerConnectioninspectofferbundlePolicybundleonlyexpectedtxt">trunk/LayoutTests/fast/mediastream/RTCPeerConnection-inspect-offer-bundlePolicy-bundle-only-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastmediastreamRTCPeerConnectioninspectofferbundlePolicybundleonlyhtml">trunk/LayoutTests/fast/mediastream/RTCPeerConnection-inspect-offer-bundlePolicy-bundle-only.html</a></li>
<li><a href="#trunkLayoutTestsplatformgtkfastmediastreamRTCPeerConnectioninspectanswerexpectedtxt">trunk/LayoutTests/platform/gtk/fast/mediastream/RTCPeerConnection-inspect-answer-expected.txt</a></li>
<li><a href="#trunkLayoutTestsplatformgtkfastmediastreamRTCPeerConnectioninspectofferexpectedtxt">trunk/LayoutTests/platform/gtk/fast/mediastream/RTCPeerConnection-inspect-offer-expected.txt</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (214959 => 214960)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2017-04-05 19:09:28 UTC (rev 214959)
+++ trunk/LayoutTests/ChangeLog        2017-04-05 19:14:36 UTC (rev 214960)
</span><span class="lines">@@ -1,3 +1,28 @@
</span><ins>+2017-04-05  Carlos Alberto Lopez Perez  &lt;clopez@igalia.com&gt;
+
+        [WebRTC][OpenWebRTC] Add support for SDP BUNDLE (&quot;a:group:BUNDLE&quot; and &quot;a=bundle-only&quot; lines)
+        https://bugs.webkit.org/show_bug.cgi?id=170157
+
+        Reviewed by Alejandro G. Castro.
+
+        The test fast/mediastream/RTCPeerConnection-inspect-offer-bundlePolicy-bundle-only.html
+        is used to check that we generate the &quot;a=bundle-only&quot; lines on the &quot;m=&quot; sections
+        according to the bundlePolicy. The 3 possible values of bundlePolicy are tested.
+        To properly test bundlePolicy:&quot;balanced&quot; we generate 5 extra tracks (6 in total)
+        for each one of the audio media type and video media type.
+
+        * TestExpectations: Set RTCPeerConnection-inspect-offer-bundlePolicy-bundle-only.html
+        as failing in the general TestExpectations, because the libwebrtc backend currently
+        doesn't generate the expected a=bundle-only lines.
+        On the GTK+ port TestExpectations file this is overriden, and the test is marked to pass.
+        The whole fast/mediastream directory is already overriden to pass.
+        * fast/mediastream/RTCPeerConnection-inspect-offer-bundlePolicy-bundle-only-expected.txt: Added.
+        * fast/mediastream/RTCPeerConnection-inspect-offer-bundlePolicy-bundle-only.html: Added.
+        * fast/mediastream/resources/sdp-utils.js:
+        (printComparableSessionDescription): Validate the a=group:BUNDLE line to contain the required MID identifiers.
+        * platform/gtk/fast/mediastream/RTCPeerConnection-inspect-answer-expected.txt: Added. Rebaseline with the expected a=group:BUNDLE line.
+        * platform/gtk/fast/mediastream/RTCPeerConnection-inspect-offer-expected.txt: Added. Rebaseline with the expected a=group:BUNDLE line.
+
</ins><span class="cx"> 2017-04-05  Jer Noble  &lt;jer.noble@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [MSE] Seeks to currentTime=0 will fail if currentTime is already 0.
</span></span></pre></div>
<a id="trunkLayoutTestsTestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/TestExpectations (214959 => 214960)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/TestExpectations        2017-04-05 19:09:28 UTC (rev 214959)
+++ trunk/LayoutTests/TestExpectations        2017-04-05 19:14:36 UTC (rev 214960)
</span><span class="lines">@@ -724,6 +724,8 @@
</span><span class="cx"> fast/mediastream/RTCRtpSender-replaceTrack.html [ Skip ]
</span><span class="cx"> fast/mediastream/RTCPeerConnection-icecandidate-event.html [ Pass Failure ]
</span><span class="cx"> fast/mediastream/RTCPeerConnection-dtmf.html [ Failure ]
</span><ins>+# libwebrtc backend doesn't generate a=bundle-only lines
+fast/mediastream/RTCPeerConnection-inspect-offer-bundlePolicy-bundle-only.html [ Failure ]
</ins><span class="cx"> 
</span><span class="cx"> # Need updating wptserve
</span><span class="cx"> imported/w3c/web-platform-tests/XMLHttpRequest/setrequestheader-content-type.htm [ Skip ]
</span></span></pre></div>
<a id="trunkLayoutTestsfastmediastreamRTCPeerConnectioninspectofferbundlePolicybundleonlyexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/mediastream/RTCPeerConnection-inspect-offer-bundlePolicy-bundle-only-expected.txt (0 => 214960)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/mediastream/RTCPeerConnection-inspect-offer-bundlePolicy-bundle-only-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/mediastream/RTCPeerConnection-inspect-offer-bundlePolicy-bundle-only-expected.txt        2017-04-05 19:14:36 UTC (rev 214960)
</span><span class="lines">@@ -0,0 +1,700 @@
</span><ins>+Inspect that the SDP offer contains the correct number of a=bundle-only lines according to the bundlePolicy value.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS Start promise chain for bundlePolicy: max-compat
+PASS Generated SDP offer for bundlePolicy: max-compat
+=== RTCSessionDescription ===
+type: offer, sdp:
+v=0
+o=- {session-id:OK} 0 IN IP4 127.0.0.1
+s=-
+t=0 0
+a=group:BUNDLE {bundle:OK}
+a=msid-semantic:WMS {media-stream-id:OK}
+m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:111 OPUS/48000/2
+a=rtpmap:8 PCMA/8000
+a=rtpmap:0 PCMU/8000
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=video 9 UDP/TLS/RTP/SAVPF 103 100 120
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:103 H264/90000
+a=rtpmap:100 VP8/90000
+a=rtpmap:120 RTX/90000
+a=fmtp:103 packetization-mode=1
+a=fmtp:120 apt=100;rtx-time=200
+a=rtcp-fb:100 nack
+a=rtcp-fb:103 nack pli
+a=rtcp-fb:100 nack pli
+a=rtcp-fb:103 ccm fir
+a=rtcp-fb:100 ccm fir
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:111 OPUS/48000/2
+a=rtpmap:8 PCMA/8000
+a=rtpmap:0 PCMU/8000
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=video 9 UDP/TLS/RTP/SAVPF 103 100 120
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:103 H264/90000
+a=rtpmap:100 VP8/90000
+a=rtpmap:120 RTX/90000
+a=fmtp:103 packetization-mode=1
+a=fmtp:120 apt=100;rtx-time=200
+a=rtcp-fb:100 nack
+a=rtcp-fb:103 nack pli
+a=rtcp-fb:100 nack pli
+a=rtcp-fb:103 ccm fir
+a=rtcp-fb:100 ccm fir
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:111 OPUS/48000/2
+a=rtpmap:8 PCMA/8000
+a=rtpmap:0 PCMU/8000
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=video 9 UDP/TLS/RTP/SAVPF 103 100 120
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:103 H264/90000
+a=rtpmap:100 VP8/90000
+a=rtpmap:120 RTX/90000
+a=fmtp:103 packetization-mode=1
+a=fmtp:120 apt=100;rtx-time=200
+a=rtcp-fb:100 nack
+a=rtcp-fb:103 nack pli
+a=rtcp-fb:100 nack pli
+a=rtcp-fb:103 ccm fir
+a=rtcp-fb:100 ccm fir
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:111 OPUS/48000/2
+a=rtpmap:8 PCMA/8000
+a=rtpmap:0 PCMU/8000
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=video 9 UDP/TLS/RTP/SAVPF 103 100 120
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:103 H264/90000
+a=rtpmap:100 VP8/90000
+a=rtpmap:120 RTX/90000
+a=fmtp:103 packetization-mode=1
+a=fmtp:120 apt=100;rtx-time=200
+a=rtcp-fb:100 nack
+a=rtcp-fb:103 nack pli
+a=rtcp-fb:100 nack pli
+a=rtcp-fb:103 ccm fir
+a=rtcp-fb:100 ccm fir
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:111 OPUS/48000/2
+a=rtpmap:8 PCMA/8000
+a=rtpmap:0 PCMU/8000
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=video 9 UDP/TLS/RTP/SAVPF 103 100 120
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:103 H264/90000
+a=rtpmap:100 VP8/90000
+a=rtpmap:120 RTX/90000
+a=fmtp:103 packetization-mode=1
+a=fmtp:120 apt=100;rtx-time=200
+a=rtcp-fb:100 nack
+a=rtcp-fb:103 nack pli
+a=rtcp-fb:100 nack pli
+a=rtcp-fb:103 ccm fir
+a=rtcp-fb:100 ccm fir
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:111 OPUS/48000/2
+a=rtpmap:8 PCMA/8000
+a=rtpmap:0 PCMU/8000
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=video 9 UDP/TLS/RTP/SAVPF 103 100 120
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:103 H264/90000
+a=rtpmap:100 VP8/90000
+a=rtpmap:120 RTX/90000
+a=fmtp:103 packetization-mode=1
+a=fmtp:120 apt=100;rtx-time=200
+a=rtcp-fb:100 nack
+a=rtcp-fb:103 nack pli
+a=rtcp-fb:100 nack pli
+a=rtcp-fb:103 ccm fir
+a=rtcp-fb:100 ccm fir
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+===
+
+PASS Generated SDP offer for bundlePolicy: max-compat. Got the expected number of a=bundle-only lines: 0
+PASS Start promise chain for bundlePolicy: balanced
+PASS Generated SDP offer for bundlePolicy: balanced
+=== RTCSessionDescription ===
+type: offer, sdp:
+v=0
+o=- {session-id:OK} 0 IN IP4 127.0.0.1
+s=-
+t=0 0
+a=group:BUNDLE {bundle:OK}
+a=msid-semantic:WMS {media-stream-id:OK}
+m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:111 OPUS/48000/2
+a=rtpmap:8 PCMA/8000
+a=rtpmap:0 PCMU/8000
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=video 9 UDP/TLS/RTP/SAVPF 103 100 120
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:103 H264/90000
+a=rtpmap:100 VP8/90000
+a=rtpmap:120 RTX/90000
+a=fmtp:103 packetization-mode=1
+a=fmtp:120 apt=100;rtx-time=200
+a=rtcp-fb:100 nack
+a=rtcp-fb:103 nack pli
+a=rtcp-fb:100 nack pli
+a=rtcp-fb:103 ccm fir
+a=rtcp-fb:100 ccm fir
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=bundle-only
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:111 OPUS/48000/2
+a=rtpmap:8 PCMA/8000
+a=rtpmap:0 PCMU/8000
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=video 9 UDP/TLS/RTP/SAVPF 103 100 120
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=bundle-only
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:103 H264/90000
+a=rtpmap:100 VP8/90000
+a=rtpmap:120 RTX/90000
+a=fmtp:103 packetization-mode=1
+a=fmtp:120 apt=100;rtx-time=200
+a=rtcp-fb:100 nack
+a=rtcp-fb:103 nack pli
+a=rtcp-fb:100 nack pli
+a=rtcp-fb:103 ccm fir
+a=rtcp-fb:100 ccm fir
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=bundle-only
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:111 OPUS/48000/2
+a=rtpmap:8 PCMA/8000
+a=rtpmap:0 PCMU/8000
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=video 9 UDP/TLS/RTP/SAVPF 103 100 120
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=bundle-only
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:103 H264/90000
+a=rtpmap:100 VP8/90000
+a=rtpmap:120 RTX/90000
+a=fmtp:103 packetization-mode=1
+a=fmtp:120 apt=100;rtx-time=200
+a=rtcp-fb:100 nack
+a=rtcp-fb:103 nack pli
+a=rtcp-fb:100 nack pli
+a=rtcp-fb:103 ccm fir
+a=rtcp-fb:100 ccm fir
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=bundle-only
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:111 OPUS/48000/2
+a=rtpmap:8 PCMA/8000
+a=rtpmap:0 PCMU/8000
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=video 9 UDP/TLS/RTP/SAVPF 103 100 120
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=bundle-only
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:103 H264/90000
+a=rtpmap:100 VP8/90000
+a=rtpmap:120 RTX/90000
+a=fmtp:103 packetization-mode=1
+a=fmtp:120 apt=100;rtx-time=200
+a=rtcp-fb:100 nack
+a=rtcp-fb:103 nack pli
+a=rtcp-fb:100 nack pli
+a=rtcp-fb:103 ccm fir
+a=rtcp-fb:100 ccm fir
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=bundle-only
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:111 OPUS/48000/2
+a=rtpmap:8 PCMA/8000
+a=rtpmap:0 PCMU/8000
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=video 9 UDP/TLS/RTP/SAVPF 103 100 120
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=bundle-only
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:103 H264/90000
+a=rtpmap:100 VP8/90000
+a=rtpmap:120 RTX/90000
+a=fmtp:103 packetization-mode=1
+a=fmtp:120 apt=100;rtx-time=200
+a=rtcp-fb:100 nack
+a=rtcp-fb:103 nack pli
+a=rtcp-fb:100 nack pli
+a=rtcp-fb:103 ccm fir
+a=rtcp-fb:100 ccm fir
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=bundle-only
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:111 OPUS/48000/2
+a=rtpmap:8 PCMA/8000
+a=rtpmap:0 PCMU/8000
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=video 9 UDP/TLS/RTP/SAVPF 103 100 120
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=bundle-only
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:103 H264/90000
+a=rtpmap:100 VP8/90000
+a=rtpmap:120 RTX/90000
+a=fmtp:103 packetization-mode=1
+a=fmtp:120 apt=100;rtx-time=200
+a=rtcp-fb:100 nack
+a=rtcp-fb:103 nack pli
+a=rtcp-fb:100 nack pli
+a=rtcp-fb:103 ccm fir
+a=rtcp-fb:100 ccm fir
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+===
+
+PASS Generated SDP offer for bundlePolicy: balanced. Got the expected number of a=bundle-only lines: 10
+PASS Start promise chain for bundlePolicy: max-bundle
+PASS Generated SDP offer for bundlePolicy: max-bundle
+=== RTCSessionDescription ===
+type: offer, sdp:
+v=0
+o=- {session-id:OK} 0 IN IP4 127.0.0.1
+s=-
+t=0 0
+a=group:BUNDLE {bundle:OK}
+a=msid-semantic:WMS {media-stream-id:OK}
+m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:111 OPUS/48000/2
+a=rtpmap:8 PCMA/8000
+a=rtpmap:0 PCMU/8000
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=video 9 UDP/TLS/RTP/SAVPF 103 100 120
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=bundle-only
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:103 H264/90000
+a=rtpmap:100 VP8/90000
+a=rtpmap:120 RTX/90000
+a=fmtp:103 packetization-mode=1
+a=fmtp:120 apt=100;rtx-time=200
+a=rtcp-fb:100 nack
+a=rtcp-fb:103 nack pli
+a=rtcp-fb:100 nack pli
+a=rtcp-fb:103 ccm fir
+a=rtcp-fb:100 ccm fir
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=bundle-only
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:111 OPUS/48000/2
+a=rtpmap:8 PCMA/8000
+a=rtpmap:0 PCMU/8000
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=video 9 UDP/TLS/RTP/SAVPF 103 100 120
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=bundle-only
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:103 H264/90000
+a=rtpmap:100 VP8/90000
+a=rtpmap:120 RTX/90000
+a=fmtp:103 packetization-mode=1
+a=fmtp:120 apt=100;rtx-time=200
+a=rtcp-fb:100 nack
+a=rtcp-fb:103 nack pli
+a=rtcp-fb:100 nack pli
+a=rtcp-fb:103 ccm fir
+a=rtcp-fb:100 ccm fir
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=bundle-only
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:111 OPUS/48000/2
+a=rtpmap:8 PCMA/8000
+a=rtpmap:0 PCMU/8000
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=video 9 UDP/TLS/RTP/SAVPF 103 100 120
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=bundle-only
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:103 H264/90000
+a=rtpmap:100 VP8/90000
+a=rtpmap:120 RTX/90000
+a=fmtp:103 packetization-mode=1
+a=fmtp:120 apt=100;rtx-time=200
+a=rtcp-fb:100 nack
+a=rtcp-fb:103 nack pli
+a=rtcp-fb:100 nack pli
+a=rtcp-fb:103 ccm fir
+a=rtcp-fb:100 ccm fir
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=bundle-only
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:111 OPUS/48000/2
+a=rtpmap:8 PCMA/8000
+a=rtpmap:0 PCMU/8000
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=video 9 UDP/TLS/RTP/SAVPF 103 100 120
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=bundle-only
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:103 H264/90000
+a=rtpmap:100 VP8/90000
+a=rtpmap:120 RTX/90000
+a=fmtp:103 packetization-mode=1
+a=fmtp:120 apt=100;rtx-time=200
+a=rtcp-fb:100 nack
+a=rtcp-fb:103 nack pli
+a=rtcp-fb:100 nack pli
+a=rtcp-fb:103 ccm fir
+a=rtcp-fb:100 ccm fir
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=bundle-only
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:111 OPUS/48000/2
+a=rtpmap:8 PCMA/8000
+a=rtpmap:0 PCMU/8000
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=video 9 UDP/TLS/RTP/SAVPF 103 100 120
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=bundle-only
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:103 H264/90000
+a=rtpmap:100 VP8/90000
+a=rtpmap:120 RTX/90000
+a=fmtp:103 packetization-mode=1
+a=fmtp:120 apt=100;rtx-time=200
+a=rtcp-fb:100 nack
+a=rtcp-fb:103 nack pli
+a=rtcp-fb:100 nack pli
+a=rtcp-fb:103 ccm fir
+a=rtcp-fb:100 ccm fir
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=bundle-only
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:111 OPUS/48000/2
+a=rtpmap:8 PCMA/8000
+a=rtpmap:0 PCMU/8000
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=video 9 UDP/TLS/RTP/SAVPF 103 100 120
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=bundle-only
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:103 H264/90000
+a=rtpmap:100 VP8/90000
+a=rtpmap:120 RTX/90000
+a=fmtp:103 packetization-mode=1
+a=fmtp:120 apt=100;rtx-time=200
+a=rtcp-fb:100 nack
+a=rtcp-fb:103 nack pli
+a=rtcp-fb:100 nack pli
+a=rtcp-fb:103 ccm fir
+a=rtcp-fb:100 ccm fir
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+===
+
+PASS Generated SDP offer for bundlePolicy: max-bundle. Got the expected number of a=bundle-only lines: 11
+PASS Tested the following bundlePolicy values: max-compat balanced max-bundle
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastmediastreamRTCPeerConnectioninspectofferbundlePolicybundleonlyhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/mediastream/RTCPeerConnection-inspect-offer-bundlePolicy-bundle-only.html (0 => 214960)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/mediastream/RTCPeerConnection-inspect-offer-bundlePolicy-bundle-only.html                                (rev 0)
+++ trunk/LayoutTests/fast/mediastream/RTCPeerConnection-inspect-offer-bundlePolicy-bundle-only.html        2017-04-05 19:14:36 UTC (rev 214960)
</span><span class="lines">@@ -0,0 +1,113 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+    &lt;head&gt;
+        &lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+        &lt;script src=&quot;./resources/sdp-utils.js&quot;&gt;&lt;/script&gt;
+    &lt;/head&gt;
+    &lt;body&gt;
+        &lt;script&gt;
+
+            description(&quot;Inspect that the SDP offer contains the correct number of a=bundle-only lines according to the bundlePolicy value.&quot;);
+
+            if (window.testRunner)
+                testRunner.setUserMediaPermission(true);
+            else {
+                debug(&quot;This test can not be run without the testRunner&quot;);
+                finishJSTest();
+            }
+
+            function testBundlePolicySDP(bundlePolicy) {
+                var mediaDescriptionVariables = [];
+                var numberOfExtraTracksPerType = 5;
+                var stream;
+                var numberOfGeneratedBundleOnlyLines = 0;
+                var numberOfExpectedBundleOnlyLines = 0;
+                var numberOfDifferentTypeTracks = 2; // audio and video
+
+                switch (bundlePolicy) {
+                    case &quot;max-compat&quot;:
+                        // None of the m= sections should have a=bundle-only.
+                        numberOfExpectedBundleOnlyLines = 0;
+                        break;
+                    case &quot;max-bundle&quot;:
+                        // All the m= sections (except the first one) should have a=bundle-only.
+                        numberOfExpectedBundleOnlyLines = numberOfDifferentTypeTracks * (numberOfExtraTracksPerType + 1 ) - 1;
+                        break;
+                     default: // balanced
+                        // All the m= sections (except the first one of each type) should have a=bundle-only.
+                        numberOfExpectedBundleOnlyLines = numberOfDifferentTypeTracks * numberOfExtraTracksPerType;
+                        break;
+                    }
+                if (numberOfExpectedBundleOnlyLines &lt; 0)
+                    numberOfExpectedBundleOnlyLines = 0;
+
+                var connectionConfig = { iceServers:[{urls:'stun:foo.com'}],
+                                         bundlePolicy: bundlePolicy };
+                var pc = new RTCPeerConnection(connectionConfig);
+
+                navigator.mediaDevices.getUserMedia({ &quot;audio&quot;: true, &quot;video&quot;: true})
+                .then(function (stream) {
+                    testPassed(&quot;Start promise chain for bundlePolicy: &quot; + bundlePolicy);
+                    var audioTrack = stream.getAudioTracks()[0];
+                    var videoTrack = stream.getVideoTracks()[0];
+                    pc.addTrack(audioTrack, stream);
+                    pc.addTrack(videoTrack, stream);
+                    mediaDescriptionVariables.push({ &quot;trackId&quot;: audioTrack.id, &quot;streamId&quot;: stream.id });
+                    mediaDescriptionVariables.push({ &quot;trackId&quot;: videoTrack.id, &quot;streamId&quot;: stream.id });
+                    for(var i=0; i &lt; numberOfExtraTracksPerType; i++){
+                        var audioTrackCloned = audioTrack.clone();
+                        var videoTrackCloned = videoTrack.clone();
+                        pc.addTrack(audioTrackCloned, stream);
+                        pc.addTrack(videoTrackCloned, stream);
+                        mediaDescriptionVariables.push({ &quot;trackId&quot;: audioTrackCloned.id, &quot;streamId&quot;: stream.id });
+                        mediaDescriptionVariables.push({ &quot;trackId&quot;: videoTrackCloned.id, &quot;streamId&quot;: stream.id });
+                    }
+                    return pc.createOffer();
+                })
+                .then(function (offer) {
+                    testPassed(&quot;Generated SDP offer for bundlePolicy: &quot; + bundlePolicy);
+                    printComparableSessionDescription(offer, mediaDescriptionVariables);
+                    offer.sdp.split(&quot;\r\n&quot;).forEach(function (line) {
+                        if (line == &quot;a=bundle-only&quot;) {
+                            numberOfGeneratedBundleOnlyLines++;
+                        };
+                    });
+                    if (numberOfExpectedBundleOnlyLines == numberOfGeneratedBundleOnlyLines) {
+                        testPassed(&quot;Generated SDP offer for bundlePolicy: &quot; + bundlePolicy + &quot;. Got the expected number of a=bundle-only lines: &quot; + numberOfGeneratedBundleOnlyLines);
+                    } else {
+                        testFailed(&quot;Generated SDP offer for bundlePolicy: &quot; + bundlePolicy + &quot;. Expected &quot; + numberOfExpectedBundleOnlyLines + &quot; a=bundle-only lines, but got &quot; + numberOfGeneratedBundleOnlyLines + &quot; lines instead.&quot;);
+                    }
+                    runNextSubTestIfNotFinished();
+
+                })
+                .catch(function (error) {
+                    testFailed(&quot;Error caught in promise chain: &quot; + error);
+                    finishJSTest();
+                });
+
+            };
+
+
+            function runNextSubTestIfNotFinished() {
+                if (subTestsCompleted == bundlePolicies.length) {
+                    testPassed(&quot;Tested the following bundlePolicy values: &quot; + bundlePolicies.join(&quot; &quot;));
+                    finishJSTest();
+                } else {
+                    testBundlePolicySDP(bundlePolicies[subTestsCompleted]);
+                    subTestsCompleted++;
+                };
+            };
+
+
+            var subTestsCompleted = 0;
+            var bundlePolicies = [&quot;max-compat&quot;, &quot;balanced&quot;, &quot;max-bundle&quot;];
+
+            runNextSubTestIfNotFinished();
+
+            window.jsTestIsAsync = true;
+            window.successfullyParsed = true;
+
+        &lt;/script&gt;
+        &lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+    &lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfastmediastreamresourcessdputilsjs"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/mediastream/resources/sdp-utils.js (214959 => 214960)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/mediastream/resources/sdp-utils.js        2017-04-05 19:09:28 UTC (rev 214959)
+++ trunk/LayoutTests/fast/mediastream/resources/sdp-utils.js        2017-04-05 19:14:36 UTC (rev 214960)
</span><span class="lines">@@ -16,10 +16,19 @@
</span><span class="cx">             &quot;msid&quot;: &quot;^a=(ssrc:\\d+ )?msid:([\\w+/\\-=]+) +([\\w+/\\-=]+).*$&quot;,
</span><span class="cx">             &quot;iceufrag&quot;: &quot;^a=ice-ufrag:([\\w+/]*).*$&quot;,
</span><span class="cx">             &quot;icepwd&quot;: &quot;^a=ice-pwd:([\\w+/]*).*$&quot;,
</span><ins>+            &quot;bundle&quot;: &quot;^a=group:BUNDLE .*$&quot;,
</ins><span class="cx">         };
</span><span class="cx"> 
</span><span class="cx">         var mdescIndex = -1;
</span><ins>+
+        var mid;
+        var mids = [];
</ins><span class="cx">         sdp.split(&quot;\r\n&quot;).forEach(function (line) {
</span><ins>+           if (mid = match(line, regexp.mid))
+                mids.push(mid[1]);
+        });
+
+        sdp.split(&quot;\r\n&quot;).forEach(function (line) {
</ins><span class="cx">             if (match(line, regexp.mline)) {
</span><span class="cx">                 // Media block (&quot;header&quot; line)
</span><span class="cx">                 mdescIndex++;
</span><span class="lines">@@ -32,6 +41,9 @@
</span><span class="cx">                     // The session-id should be a number between 0 and LLONG_MAX (2^63-1).
</span><span class="cx">                     if (sessid &gt;= 0 &amp;&amp; sessid &lt;= 9223372036854775807)
</span><span class="cx">                         line = line.replace(oline[2], verified(&quot;session-id&quot;));
</span><ins>+                } else if (match(line, regexp.bundle)) {
+                    if (mids.length &gt; 0)
+                        line = line.replace(&quot;a=group:BUNDLE &quot; + mids.join(&quot; &quot;), &quot;a=group:BUNDLE &quot; + verified(&quot;bundle&quot;));
</ins><span class="cx">                 } else if (match(line, regexp.msidsemantic)) {
</span><span class="cx">                     mdescVariables.forEach(function (variables) {
</span><span class="cx">                         line = line.replace(variables.streamId, verified(&quot;media-stream-id&quot;));
</span><span class="lines">@@ -40,7 +52,6 @@
</span><span class="cx">             } else {
</span><span class="cx">                 // Media block (content lines)
</span><span class="cx">                 var cname;
</span><del>-                var mid;
</del><span class="cx">                 var msid;
</span><span class="cx">                 var iceufrag;
</span><span class="cx">                 var icepwd;
</span><span class="lines">@@ -49,7 +60,7 @@
</span><span class="cx">                     line = line.replace(cname[1], verified(&quot;ssrc&quot;));
</span><span class="cx">                     line = line.replace(cname[2], verified(&quot;cname&quot;));
</span><span class="cx">                 } else if (mid = match(line, regexp.mid))
</span><del>-                    line = line.replace(mid[1], verified(&quot;mid&quot;))
</del><ins>+                    line = line.replace(mid[1], verified(&quot;mid&quot;));
</ins><span class="cx">                 else if (msid = match(line, regexp.msid)) {
</span><span class="cx">                     if (msid[1])
</span><span class="cx">                         line = line.replace(msid[1], verified(&quot;ssrc&quot;));
</span></span></pre></div>
<a id="trunkLayoutTestsplatformgtkfastmediastreamRTCPeerConnectioninspectanswerexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/platform/gtk/fast/mediastream/RTCPeerConnection-inspect-answer-expected.txt (0 => 214960)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/gtk/fast/mediastream/RTCPeerConnection-inspect-answer-expected.txt                                (rev 0)
+++ trunk/LayoutTests/platform/gtk/fast/mediastream/RTCPeerConnection-inspect-answer-expected.txt        2017-04-05 19:14:36 UTC (rev 214960)
</span><span class="lines">@@ -0,0 +1,75 @@
</span><ins>+Test RTCPeerConnection.setRemoteDescription called with an RTCSessionDescription of type 'offer'
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS Answer with audio created
+=== RTCSessionDescription ===
+type: answer, sdp:
+v=0
+o=- {session-id:OK} 0 IN IP4 127.0.0.1
+s=-
+t=0 0
+a=group:BUNDLE {bundle:OK}
+m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=recvonly
+a=mid:{mid:OK}
+a=rtpmap:111 OPUS/48000/2
+a=rtpmap:8 PCMA/8000
+a=rtpmap:0 PCMU/8000
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:active
+===
+
+PASS Answer with audio and video created
+=== RTCSessionDescription ===
+type: answer, sdp:
+v=0
+o=- {session-id:OK} 1 IN IP4 127.0.0.1
+s=-
+t=0 0
+a=group:BUNDLE {bundle:OK}
+m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=recvonly
+a=mid:{mid:OK}
+a=rtpmap:111 OPUS/48000/2
+a=rtpmap:8 PCMA/8000
+a=rtpmap:0 PCMU/8000
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:active
+m=video 9 UDP/TLS/RTP/SAVPF 103 100 120
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=recvonly
+a=mid:{mid:OK}
+a=rtpmap:103 H264/90000
+a=rtpmap:100 VP8/90000
+a=rtpmap:120 RTX/90000
+a=fmtp:103 packetization-mode=1
+a=fmtp:120 apt=100;rtx-time=200
+a=rtcp-fb:100 nack
+a=rtcp-fb:103 nack pli
+a=rtcp-fb:100 nack pli
+a=rtcp-fb:103 ccm fir
+a=rtcp-fb:100 ccm fir
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:active
+===
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsplatformgtkfastmediastreamRTCPeerConnectioninspectofferexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/platform/gtk/fast/mediastream/RTCPeerConnection-inspect-offer-expected.txt (0 => 214960)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/gtk/fast/mediastream/RTCPeerConnection-inspect-offer-expected.txt                                (rev 0)
+++ trunk/LayoutTests/platform/gtk/fast/mediastream/RTCPeerConnection-inspect-offer-expected.txt        2017-04-05 19:14:36 UTC (rev 214960)
</span><span class="lines">@@ -0,0 +1,81 @@
</span><ins>+Inspect the result of RTCPeerConnection.createOffer()
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS Got offer
+=== RTCSessionDescription ===
+type: offer, sdp:
+v=0
+o=- {session-id:OK} 0 IN IP4 127.0.0.1
+s=-
+t=0 0
+a=group:BUNDLE {bundle:OK}
+a=msid-semantic:WMS {media-stream-id:OK}
+m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:111 OPUS/48000/2
+a=rtpmap:8 PCMA/8000
+a=rtpmap:0 PCMU/8000
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+===
+
+PASS Got offer
+=== RTCSessionDescription ===
+type: offer, sdp:
+v=0
+o=- {session-id:OK} 1 IN IP4 127.0.0.1
+s=-
+t=0 0
+a=group:BUNDLE {bundle:OK}
+a=msid-semantic:WMS {media-stream-id:OK}
+m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:111 OPUS/48000/2
+a=rtpmap:8 PCMA/8000
+a=rtpmap:0 PCMU/8000
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=video 9 UDP/TLS/RTP/SAVPF 103 100 120
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendrecv
+a=mid:{mid:OK}
+a=rtpmap:103 H264/90000
+a=rtpmap:100 VP8/90000
+a=rtpmap:120 RTX/90000
+a=fmtp:103 packetization-mode=1
+a=fmtp:120 apt=100;rtx-time=200
+a=rtcp-fb:100 nack
+a=rtcp-fb:103 nack pli
+a=rtcp-fb:100 nack pli
+a=rtcp-fb:103 ccm fir
+a=rtcp-fb:100 ccm fir
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+===
+
+PASS End of promise chain
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (214959 => 214960)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2017-04-05 19:09:28 UTC (rev 214959)
+++ trunk/Source/WebCore/ChangeLog        2017-04-05 19:14:36 UTC (rev 214960)
</span><span class="lines">@@ -1,3 +1,31 @@
</span><ins>+2017-04-05  Carlos Alberto Lopez Perez  &lt;clopez@igalia.com&gt;
+
+        [WebRTC][OpenWebRTC] Add support for SDP BUNDLE (&quot;a:group:BUNDLE&quot; and &quot;a=bundle-only&quot; lines)
+        https://bugs.webkit.org/show_bug.cgi?id=170157
+
+        Reviewed by Alejandro G. Castro.
+
+        This implements support on the SDPProcessor for generating an &quot;a=group:BUNDLE&quot;
+        attribute with the MID identifiers specified in the bundle group in the most
+        recent answer.
+        It also implements support for generating &quot;a=bundle-only&quot; attributes on the
+        &quot;m=&quot; sections of the SDP according to the bundlePolicy defined.
+
+        Test: fast/mediastream/RTCPeerConnection-inspect-offer-bundlePolicy-bundle-only.html
+
+        * Modules/mediastream/MediaEndpointPeerConnection.cpp:
+        (WebCore::MediaEndpointPeerConnection::createOfferTask):
+        (WebCore::MediaEndpointPeerConnection::createAnswerTask):
+        * Modules/mediastream/SDPProcessor.cpp:
+        (WebCore::getBundlePolicyName):
+        (WebCore::configurationToJSON):
+        * Modules/mediastream/sdp.js:
+        (SDP.generate):
+        * platform/mediastream/MediaEndpointSessionConfiguration.h:
+        (WebCore::MediaEndpointSessionConfiguration::bundlePolicy):
+        (WebCore::MediaEndpointSessionConfiguration::setBundlePolicy):
+        (WebCore::MediaEndpointSessionConfiguration::clone):
+
</ins><span class="cx"> 2017-04-05  Jer Noble  &lt;jer.noble@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [MSE] Seeks to currentTime=0 will fail if currentTime is already 0.
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediastreamMediaEndpointPeerConnectioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.cpp (214959 => 214960)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.cpp        2017-04-05 19:09:28 UTC (rev 214959)
+++ trunk/Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.cpp        2017-04-05 19:14:36 UTC (rev 214960)
</span><span class="lines">@@ -159,6 +159,7 @@
</span><span class="cx">     RefPtr&lt;MediaEndpointSessionConfiguration&gt; configurationSnapshot = localDescription ?
</span><span class="cx">         localDescription-&gt;configuration()-&gt;clone() : MediaEndpointSessionConfiguration::create();
</span><span class="cx"> 
</span><ins>+    configurationSnapshot-&gt;setBundlePolicy(m_peerConnection.getConfiguration().bundlePolicy);
</ins><span class="cx">     configurationSnapshot-&gt;setSessionVersion(m_sdpOfferSessionVersion++);
</span><span class="cx"> 
</span><span class="cx">     auto transceivers = RtpTransceiverVector(m_peerConnection.getTransceivers());
</span><span class="lines">@@ -237,6 +238,7 @@
</span><span class="cx">     RefPtr&lt;MediaEndpointSessionConfiguration&gt; configurationSnapshot = localDescription ?
</span><span class="cx">         localDescription-&gt;configuration()-&gt;clone() : MediaEndpointSessionConfiguration::create();
</span><span class="cx"> 
</span><ins>+    configurationSnapshot-&gt;setBundlePolicy(m_peerConnection.getConfiguration().bundlePolicy);
</ins><span class="cx">     configurationSnapshot-&gt;setSessionVersion(m_sdpAnswerSessionVersion++);
</span><span class="cx"> 
</span><span class="cx">     auto transceivers = RtpTransceiverVector(m_peerConnection.getTransceivers());
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediastreamSDPProcessorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediastream/SDPProcessor.cpp (214959 => 214960)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediastream/SDPProcessor.cpp        2017-04-05 19:09:28 UTC (rev 214959)
+++ trunk/Source/WebCore/Modules/mediastream/SDPProcessor.cpp        2017-04-05 19:14:36 UTC (rev 214960)
</span><span class="lines">@@ -57,6 +57,7 @@
</span><span class="cx"> 
</span><span class="cx"> STRING_FUNCTION(address)
</span><span class="cx"> STRING_FUNCTION(apt)
</span><ins>+STRING_FUNCTION(bundlePolicy)
</ins><span class="cx"> STRING_FUNCTION(candidates)
</span><span class="cx"> STRING_FUNCTION(ccmfir)
</span><span class="cx"> STRING_FUNCTION(channels)
</span><span class="lines">@@ -340,9 +341,23 @@
</span><span class="cx">     return createCandidate(*candidateObject);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static String getBundlePolicyName(const PeerConnectionStates::BundlePolicy bundlePolicy)
+{
+    switch (bundlePolicy) {
+    case PeerConnectionStates::BundlePolicy::MaxCompat:
+        return &quot;max-compat&quot;;
+    case PeerConnectionStates::BundlePolicy::MaxBundle:
+        return &quot;max-bundle&quot;;
+    case PeerConnectionStates::BundlePolicy::Balanced:
+    default:
+        return &quot;balanced&quot;;
+    };
+}
+
</ins><span class="cx"> static String configurationToJSON(const MediaEndpointSessionConfiguration&amp; configuration)
</span><span class="cx"> {
</span><span class="cx">     RefPtr&lt;InspectorObject&gt; object = InspectorObject::create();
</span><ins>+    object-&gt;setString(bundlePolicyString(), getBundlePolicyName(configuration.bundlePolicy()));
</ins><span class="cx"> 
</span><span class="cx">     RefPtr&lt;InspectorObject&gt; originatorObject = InspectorObject::create();
</span><span class="cx">     originatorObject-&gt;setString(sessionIdString(), String::number(configuration.sessionId()));
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediastreamsdpjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediastream/sdp.js (214959 => 214960)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediastream/sdp.js        2017-04-05 19:09:28 UTC (rev 214959)
+++ trunk/Source/WebCore/Modules/mediastream/sdp.js        2017-04-05 19:14:36 UTC (rev 214960)
</span><span class="lines">@@ -68,6 +68,7 @@
</span><span class="cx">             &quot;o=${username} ${sessionId} ${sessionVersion} ${netType} ${addressType} ${address}\r\n&quot; +
</span><span class="cx">             &quot;s=${sessionName}\r\n&quot; +
</span><span class="cx">             &quot;t=${startTime} ${stopTime}\r\n&quot; +
</span><ins>+            &quot;${bundleLine}&quot; +
</ins><span class="cx">             &quot;${msidsemanticLine}&quot;,
</span><span class="cx"> 
</span><span class="cx">         &quot;msidsemantic&quot;: &quot;a=msid-semantic:WMS ${mediaStreamIds}\r\n&quot;,
</span><span class="lines">@@ -77,6 +78,7 @@
</span><span class="cx">             &quot;c=${netType} ${addressType} ${address}\r\n&quot; +
</span><span class="cx">             &quot;${rtcpLine}&quot; +
</span><span class="cx">             &quot;${rtcpMuxLine}&quot; +
</span><ins>+            &quot;${bundleOnlyLine}&quot; +
</ins><span class="cx">             &quot;a=${mode}\r\n&quot; +
</span><span class="cx">             &quot;${midLine}&quot; +
</span><span class="cx">             &quot;${rtpMapLines}&quot; +
</span><span class="lines">@@ -96,6 +98,7 @@
</span><span class="cx">         &quot;rtcp&quot;: &quot;a=rtcp:${port}${[ ]netType}${[ ]addressType}${[ ]address}\r\n&quot;,
</span><span class="cx">         &quot;rtcpMux&quot;: &quot;a=rtcp-mux\r\n&quot;,
</span><span class="cx">         &quot;mid&quot;: &quot;a=mid:${mid}\r\n&quot;,
</span><ins>+        &quot;bundle&quot;: &quot;a=group:BUNDLE ${midsBundle}\r\n&quot;,
</ins><span class="cx"> 
</span><span class="cx">         &quot;rtpMap&quot;: &quot;a=rtpmap:${type} ${encodingName}/${clockRate}${[/]channels}\r\n&quot;,
</span><span class="cx">         &quot;fmtp&quot;: &quot;a=fmtp:${type} ${parameters}\r\n&quot;,
</span><span class="lines">@@ -373,6 +376,7 @@
</span><span class="cx">             &quot;sessionName&quot;: &quot;-&quot;,
</span><span class="cx">             &quot;startTime&quot;: 0,
</span><span class="cx">             &quot;stopTime&quot;: 0,
</span><ins>+            &quot;bundlePolicy&quot;: &quot;balanced&quot;,
</ins><span class="cx">             &quot;mediaDescriptions&quot;: []
</span><span class="cx">         });
</span><span class="cx">         addDefaults(sdpObj.originator, {
</span><span class="lines">@@ -386,6 +390,8 @@
</span><span class="cx">         var sdpText = fillTemplate(templates.sdp, sdpObj);
</span><span class="cx">         sdpText = fillTemplate(sdpText, sdpObj.originator);
</span><span class="cx"> 
</span><ins>+        var midsBundle = [];
+        var mediatypesBundle = [];
</ins><span class="cx">         var msidsemanticLine = &quot;&quot;;
</span><span class="cx">         var mediaStreamIds = [];
</span><span class="cx">         sdpObj.mediaDescriptions.forEach(function (mdesc) {
</span><span class="lines">@@ -412,10 +418,16 @@
</span><span class="cx">             });
</span><span class="cx">             var mblock = fillTemplate(templates.mblock, mediaDescription);
</span><span class="cx"> 
</span><del>-            var midInfo = {&quot;midLine&quot;: &quot;&quot;};
-            if (mediaDescription.mid)
-                midInfo.midLine = fillTemplate(templates.mid, mediaDescription);
-            mblock = fillTemplate(mblock, midInfo);
</del><ins>+            var midBundleInfo = {&quot;midLine&quot;: &quot;&quot;, &quot;bundleOnlyLine&quot;: &quot;&quot;};
+            if (mediaDescription.mid) {
+                midBundleInfo.midLine = fillTemplate(templates.mid, mediaDescription);
+                if ((sdpObj.bundlePolicy == &quot;balanced&quot;   &amp;&amp; mediatypesBundle.includes(mediaDescription.type)) ||
+                    (sdpObj.bundlePolicy == &quot;max-bundle&quot; &amp;&amp; mediatypesBundle.length &gt; 0))
+                    midBundleInfo.bundleOnlyLine = &quot;a=bundle-only\r\n&quot;;
+                mediatypesBundle.push(mediaDescription.type)
+                midsBundle.push(mediaDescription.mid);
+            }
+            mblock = fillTemplate(mblock, midBundleInfo);
</ins><span class="cx"> 
</span><span class="cx">             var payloadInfo = {&quot;rtpMapLines&quot;: &quot;&quot;, &quot;fmtpLines&quot;: &quot;&quot;, &quot;nackLines&quot;: &quot;&quot;,
</span><span class="cx">                 &quot;nackpliLines&quot;: &quot;&quot;, &quot;ccmfirLines&quot;: &quot;&quot;, &quot;ericScreamLines&quot;: &quot;&quot;};
</span><span class="lines">@@ -523,6 +535,11 @@
</span><span class="cx">             sdpText += mblock;
</span><span class="cx">         });
</span><span class="cx"> 
</span><ins>+        var bundleLine = &quot;&quot;;
+        if (midsBundle.length &gt; 0)
+            bundleLine = fillTemplate(templates.bundle, { &quot;midsBundle&quot;: midsBundle.join(&quot; &quot;) });
+        sdpText = fillTemplate(sdpText, { &quot;bundleLine&quot;: bundleLine });
+
</ins><span class="cx">         return sdpText;
</span><span class="cx">     };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreamMediaEndpointSessionConfigurationh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/MediaEndpointSessionConfiguration.h (214959 => 214960)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/MediaEndpointSessionConfiguration.h        2017-04-05 19:09:28 UTC (rev 214959)
+++ trunk/Source/WebCore/platform/mediastream/MediaEndpointSessionConfiguration.h        2017-04-05 19:14:36 UTC (rev 214960)
</span><span class="lines">@@ -33,6 +33,7 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(WEB_RTC)
</span><span class="cx"> 
</span><ins>+#include &quot;PeerConnectionStates.h&quot;
</ins><span class="cx"> #include &quot;PeerMediaDescription.h&quot;
</span><span class="cx"> #include &lt;wtf/CryptographicallyRandomNumber.h&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -56,6 +57,9 @@
</span><span class="cx">     const Vector&lt;PeerMediaDescription&gt;&amp; mediaDescriptions() const { return m_mediaDescriptions; }
</span><span class="cx">     void addMediaDescription(PeerMediaDescription&amp;&amp; description) { m_mediaDescriptions.append(WTFMove(description)); }
</span><span class="cx"> 
</span><ins>+    PeerConnectionStates::BundlePolicy bundlePolicy() const { return m_bundlePolicy; }
+    void setBundlePolicy(PeerConnectionStates::BundlePolicy bundlePolicy) { m_bundlePolicy = bundlePolicy; }
+
</ins><span class="cx">     RefPtr&lt;MediaEndpointSessionConfiguration&gt; clone() const
</span><span class="cx">     {
</span><span class="cx">         RefPtr&lt;MediaEndpointSessionConfiguration&gt; copy = create();
</span><span class="lines">@@ -62,6 +66,7 @@
</span><span class="cx">         copy-&gt;m_sessionId = m_sessionId;
</span><span class="cx">         copy-&gt;m_sessionVersion = m_sessionVersion;
</span><span class="cx">         copy-&gt;m_mediaDescriptions = m_mediaDescriptions;
</span><ins>+        copy-&gt;m_bundlePolicy = m_bundlePolicy;
</ins><span class="cx"> 
</span><span class="cx">         return copy;
</span><span class="cx">     }
</span><span class="lines">@@ -77,6 +82,8 @@
</span><span class="cx">     unsigned m_sessionVersion { 0 };
</span><span class="cx"> 
</span><span class="cx">     Vector&lt;PeerMediaDescription&gt; m_mediaDescriptions;
</span><ins>+
+    PeerConnectionStates::BundlePolicy m_bundlePolicy { PeerConnectionStates::BundlePolicy::Balanced };
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre>
</div>
</div>

</body>
</html>