<!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>[208940] trunk/Tools</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/208940">208940</a></dd>
<dt>Author</dt> <dd>philn@webkit.org</dd>
<dt>Date</dt> <dd>2016-11-21 00:09:03 -0800 (Mon, 21 Nov 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>[GTK][WebRTC] Switch to downstream OpenWebRTC and more recent GStreamer
https://bugs.webkit.org/show_bug.cgi?id=164817

Reviewed by Alejandro G. Castro.

This is temporary, hopefully. The OpenWebRTC patches will/should
be soon reviewed and upstream but meanwhile it makes sense to use
the Igalia downstream fork so that the WebRTC testing is easier.

Recent GStreamer patches are also needed for RTP bundling support
and RTP retransmission fixes.

* gtk/jhbuild.modules:
* gtk/openwebrtc.modules: Removed.
* gtk/patches/gst-plugins-good-0001-rtpbin-pipeline-gets-an-EOS-when-any-rtpsources-byes.patch: Added.
* gtk/patches/gst-plugins-good-0002-rtpbin-avoid-generating-errors-when-rtcp-messages-ar.patch: Added.
* gtk/patches/gst-plugins-good-0003-rtpbin-receive-bundle-support.patch: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsgtkjhbuildmodules">trunk/Tools/gtk/jhbuild.modules</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkToolsgtkpatchesgstpluginsgood0001rtpbinpipelinegetsanEOSwhenanyrtpsourcesbyespatch">trunk/Tools/gtk/patches/gst-plugins-good-0001-rtpbin-pipeline-gets-an-EOS-when-any-rtpsources-byes.patch</a></li>
<li><a href="#trunkToolsgtkpatchesgstpluginsgood0002rtpbinavoidgeneratingerrorswhenrtcpmessagesarpatch">trunk/Tools/gtk/patches/gst-plugins-good-0002-rtpbin-avoid-generating-errors-when-rtcp-messages-ar.patch</a></li>
<li><a href="#trunkToolsgtkpatchesgstpluginsgood0003rtpbinreceivebundlesupportpatch">trunk/Tools/gtk/patches/gst-plugins-good-0003-rtpbin-receive-bundle-support.patch</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#trunkToolsgtkopenwebrtcmodules">trunk/Tools/gtk/openwebrtc.modules</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (208939 => 208940)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2016-11-21 06:22:39 UTC (rev 208939)
+++ trunk/Tools/ChangeLog        2016-11-21 08:09:03 UTC (rev 208940)
</span><span class="lines">@@ -1,3 +1,23 @@
</span><ins>+2016-11-16  Philippe Normand  &lt;pnormand@igalia.com&gt;
+
+        [GTK][WebRTC] Switch to downstream OpenWebRTC and more recent GStreamer
+        https://bugs.webkit.org/show_bug.cgi?id=164817
+
+        Reviewed by Alejandro G. Castro.
+
+        This is temporary, hopefully. The OpenWebRTC patches will/should
+        be soon reviewed and upstream but meanwhile it makes sense to use
+        the Igalia downstream fork so that the WebRTC testing is easier.
+
+        Recent GStreamer patches are also needed for RTP bundling support
+        and RTP retransmission fixes.
+
+        * gtk/jhbuild.modules:
+        * gtk/openwebrtc.modules: Removed.
+        * gtk/patches/gst-plugins-good-0001-rtpbin-pipeline-gets-an-EOS-when-any-rtpsources-byes.patch: Added.
+        * gtk/patches/gst-plugins-good-0002-rtpbin-avoid-generating-errors-when-rtcp-messages-ar.patch: Added.
+        * gtk/patches/gst-plugins-good-0003-rtpbin-receive-bundle-support.patch: Added.
+
</ins><span class="cx"> 2016-11-20  Zan Dobersek  &lt;zdobersek@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [EncryptedMedia] Make EME API runtime-enabled
</span></span></pre></div>
<a id="trunkToolsgtkjhbuildmodules"></a>
<div class="modfile"><h4>Modified: trunk/Tools/gtk/jhbuild.modules (208939 => 208940)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/gtk/jhbuild.modules        2016-11-21 06:22:39 UTC (rev 208939)
+++ trunk/Tools/gtk/jhbuild.modules        2016-11-21 08:09:03 UTC (rev 208940)
</span><span class="lines">@@ -48,6 +48,8 @@
</span><span class="cx">   &lt;!-- Please use http/https to access repositories to be friendly to users stuck behind firewalls. --&gt;
</span><span class="cx">   &lt;repository type=&quot;git&quot; name=&quot;github.com&quot;
</span><span class="cx">       href=&quot;https://github.com&quot;/&gt;
</span><ins>+  &lt;repository type=&quot;tarball&quot; name=&quot;github-tarball&quot;
+      href=&quot;https://github.com/&quot;/&gt;
</ins><span class="cx">   &lt;repository type=&quot;tarball&quot; name=&quot;sourceware.org-mirror&quot;
</span><span class="cx">       href=&quot;http://mirrors.kernel.org/sources.redhat.com/&quot;/&gt;
</span><span class="cx">   &lt;repository type=&quot;tarball&quot; name=&quot;ftp.gnome.org&quot;
</span><span class="lines">@@ -385,6 +387,9 @@
</span><span class="cx">             md5sum=&quot;91ed4649c7c2e43a61f731d144f6f6d0&quot;&gt;
</span><span class="cx">       &lt;patch file=&quot;gst-plugins-good-use-the-tfdt-decode-time.patch&quot; strip=&quot;1&quot;/&gt;
</span><span class="cx">       &lt;patch file=&quot;gst-plugins-good-Revert-qtdemux-expose-streams-with-first-moof-for-fr.patch&quot; strip=&quot;1&quot;/&gt;
</span><ins>+      &lt;patch file=&quot;gst-plugins-good-0001-rtpbin-pipeline-gets-an-EOS-when-any-rtpsources-byes.patch&quot; strip=&quot;1&quot;/&gt;
+      &lt;patch file=&quot;gst-plugins-good-0002-rtpbin-avoid-generating-errors-when-rtcp-messages-ar.patch&quot; strip=&quot;1&quot;/&gt;
+      &lt;patch file=&quot;gst-plugins-good-0003-rtpbin-receive-bundle-support.patch&quot; strip=&quot;1&quot;/&gt;
</ins><span class="cx">     &lt;/branch&gt;
</span><span class="cx">   &lt;/autotools&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -492,21 +497,38 @@
</span><span class="cx"> 
</span><span class="cx">   &lt;autotools id=&quot;libusrsctp&quot; supports-non-srcdir-builds=&quot;no&quot; autogen-sh=&quot;./bootstrap; ./configure --disable-warnings-as-errors&quot;&gt;
</span><span class="cx">     &lt;branch repo=&quot;github.com&quot; module=&quot;sctplab/usrsctp.git&quot; checkoutdir=&quot;usrsctp&quot; tag=&quot;078ff3252f73327e0ac11d6fd5eff62011f6646e&quot;/&gt;
</span><del>-   &lt;/autotools&gt;
</del><ins>+  &lt;/autotools&gt;
</ins><span class="cx"> 
</span><ins>+  &lt;autotools id=&quot;openh264&quot; supports-non-srcdir-builds=&quot;no&quot; autogen-sh=&quot;pseudo-configure&quot;&gt;
+    &lt;branch module=&quot;cisco/openh264/archive/v${version}.tar.gz&quot; version=&quot;1.5.0&quot;
+            checkoutdir=&quot;openh264-${version}&quot; repo=&quot;github-tarball&quot;&gt;
+      &lt;patch file=&quot;openh264-configure.patch&quot; strip=&quot;0&quot;/&gt;
+    &lt;/branch&gt;
+  &lt;/autotools&gt;
+
+  &lt;autotools id=&quot;libvpx&quot;
+    autogen-template=&quot;%(srcdir)s/configure --prefix=%(prefix)s --enable-pic --as=yasm --disable-unit-tests --size-limit=16384x16384 --enable-postproc --enable-multi-res-encoding --enable-temporal-denoising --enable-vp9-temporal-denoising --enable-vp9-postproc --enable-shared&quot;&gt;
+    &lt;branch repo=&quot;github.com&quot; module=&quot;webmproject/libvpx.git&quot; version=&quot;1.6.0&quot; checkoutdir=&quot;libvpx-1.6.0&quot;&gt;
+    &lt;/branch&gt;
+  &lt;/autotools&gt;
+
</ins><span class="cx">    &lt;autotools id=&quot;gst-plugins-openwebrtc&quot; supports-parallel-builds=&quot;no&quot; supports-non-srcdir-builds=&quot;no&quot; autogen-sh=&quot;./autogen.sh; ./configure&quot;&gt;
</span><span class="cx">      &lt;dependencies&gt;
</span><span class="cx">        &lt;dep package=&quot;gst-plugins-base&quot;/&gt;
</span><span class="cx">        &lt;dep package=&quot;libusrsctp&quot;/&gt;
</span><span class="cx">      &lt;/dependencies&gt;
</span><del>-    &lt;branch repo=&quot;github.com&quot; module=&quot;EricssonResearch/openwebrtc-gst-plugins.git&quot; checkoutdir=&quot;gst-plugins-openwebrtc&quot; tag=&quot;f40f3302007da00f0bfb82065d705b62c2ea1afd&quot;/&gt;
</del><ins>+    &lt;branch repo=&quot;github.com&quot; module=&quot;Igalia/openwebrtc-gst-plugins.git&quot; checkoutdir=&quot;gst-plugins-openwebrtc&quot; tag=&quot;9b2199ea970369dbf1d9ca2f8e61c95f21db2b6e&quot;/&gt;
</ins><span class="cx">    &lt;/autotools&gt;
</span><span class="cx"> 
</span><del>-   &lt;autotools id=&quot;libnice&quot; supports-non-srcdir-builds=&quot;no&quot;&gt;
</del><ins>+  &lt;autotools id=&quot;libnice&quot; supports-non-srcdir-builds=&quot;no&quot;&gt;
</ins><span class="cx">     &lt;dependencies&gt;
</span><span class="cx">       &lt;dep package=&quot;gstreamer&quot;/&gt;
</span><span class="cx">     &lt;/dependencies&gt;
</span><del>-    &lt;branch repo=&quot;freedesktop-git&quot; module=&quot;libnice/libnice.git&quot; tag=&quot;0.1.13&quot; checkoutdir=&quot;libnice&quot;/&gt;
</del><ins>+    &lt;branch module=&quot;libnice/libnice/archive/${version}.tar.gz&quot; version=&quot;2803a0b4b70af9684e05ef5ed3f0c2fbca4b6c93&quot;
+            checkoutdir=&quot;libnice-${version}&quot; repo=&quot;github-tarball&quot;&gt;
+      &lt;patch file=&quot;libnice-0001-nicesrc-spin-the-agent-mainloop-in-a-separate-thread.patch&quot; strip=&quot;1&quot;/&gt;
+      &lt;patch file=&quot;libnice-0001-TURN-allow-REALM-to-be-empty.patch&quot; strip=&quot;1&quot;/&gt;
+    &lt;/branch&gt;
</ins><span class="cx">   &lt;/autotools&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;autotools id=&quot;openwebrtc&quot; autogenargs=&quot;--enable-bridge=no --enable-owr-gst=yes&quot;&gt;
</span><span class="lines">@@ -515,7 +537,7 @@
</span><span class="cx">       &lt;dep package=&quot;gst-plugins-bad&quot;/&gt;
</span><span class="cx">       &lt;dep package=&quot;libnice&quot;/&gt;
</span><span class="cx">      &lt;/dependencies&gt;
</span><del>-    &lt;branch repo=&quot;github.com&quot; module=&quot;EricssonResearch/openwebrtc.git&quot; checkoutdir=&quot;openwebrtc&quot; tag=&quot;0b28b080d61af3adb1f779e693fc029f9c1ad499&quot;/&gt;
</del><ins>+    &lt;branch repo=&quot;github.com&quot; module=&quot;Igalia/openwebrtc.git&quot; checkoutdir=&quot;openwebrtc&quot; tag=&quot;7f3d23e034818893db198f4b56e41609abd8847b&quot;/&gt;
</ins><span class="cx">   &lt;/autotools&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;autotools id=&quot;llvm&quot;
</span></span></pre></div>
<a id="trunkToolsgtkopenwebrtcmodules"></a>
<div class="delfile"><h4>Deleted: trunk/Tools/gtk/openwebrtc.modules (208939 => 208940)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/gtk/openwebrtc.modules        2016-11-21 06:22:39 UTC (rev 208939)
+++ trunk/Tools/gtk/openwebrtc.modules        2016-11-21 08:09:03 UTC (rev 208940)
</span><span class="lines">@@ -1,81 +0,0 @@
</span><del>-&lt;?xml version=&quot;1.0&quot;?&gt;
-&lt;!DOCTYPE moduleset SYSTEM &quot;moduleset.dtd&quot;&gt;
-&lt;?xml-stylesheet type=&quot;text/xsl&quot; href=&quot;moduleset.xsl&quot;?&gt;
-&lt;moduleset&gt;
-
-  &lt;repository type=&quot;tarball&quot; name=&quot;github-tarball&quot;
-      href=&quot;https://github.com/&quot;/&gt;
-  &lt;repository type=&quot;git&quot; name=&quot;gstreamer&quot;
-      href=&quot;git://anongit.freedesktop.org/git/gstreamer/&quot;/&gt;
-  &lt;repository type=&quot;git&quot; name=&quot;github.com&quot;
-      href=&quot;https://github.com&quot;/&gt;
-
-  &lt;autotools id=&quot;openh264&quot; supports-non-srcdir-builds=&quot;no&quot; autogen-sh=&quot;pseudo-configure&quot;&gt;
-    &lt;branch module=&quot;cisco/openh264/archive/v${version}.tar.gz&quot; version=&quot;1.5.0&quot;
-            checkoutdir=&quot;openh264-${version}&quot; repo=&quot;github-tarball&quot;&gt;
-      &lt;patch file=&quot;openh264-configure.patch&quot; strip=&quot;0&quot;/&gt;
-    &lt;/branch&gt;
-  &lt;/autotools&gt;
-
-  &lt;autotools id=&quot;libvpx&quot;
-    autogen-template=&quot;%(srcdir)s/configure --prefix=%(prefix)s --enable-pic --as=yasm --disable-unit-tests --size-limit=16384x16384 --enable-postproc --enable-multi-res-encoding --enable-temporal-denoising --enable-vp9-temporal-denoising --enable-vp9-postproc --enable-shared&quot;&gt;
-    &lt;branch repo=&quot;github.com&quot; module=&quot;webmproject/libvpx.git&quot; version=&quot;1.6.0&quot; checkoutdir=&quot;libvpx-1.6.0&quot;&gt;
-    &lt;/branch&gt;
-  &lt;/autotools&gt;
-
-  &lt;autotools id=&quot;libnice&quot; supports-non-srcdir-builds=&quot;no&quot;&gt;
-    &lt;dependencies&gt;
-      &lt;dep package=&quot;gstreamer&quot;/&gt;
-    &lt;/dependencies&gt;
-    &lt;branch module=&quot;libnice/libnice/archive/${version}.tar.gz&quot; version=&quot;2803a0b4b70af9684e05ef5ed3f0c2fbca4b6c93&quot;
-            checkoutdir=&quot;libnice-${version}&quot; repo=&quot;github-tarball&quot;&gt;
-      &lt;patch file=&quot;libnice-0001-nicesrc-spin-the-agent-mainloop-in-a-separate-thread.patch&quot; strip=&quot;1&quot;/&gt;
-      &lt;patch file=&quot;libnice-0001-TURN-allow-REALM-to-be-empty.patch&quot; strip=&quot;1&quot;/&gt;
-    &lt;/branch&gt;
-  &lt;/autotools&gt;
-
-  &lt;autotools id=&quot;gstreamer&quot; autogenargs=&quot;--disable-gtk-doc&quot;&gt;
-    &lt;if condition-set=&quot;macos&quot;&gt;
-      &lt;autogenargs value=&quot;--disable-introspection&quot;/&gt;
-    &lt;/if&gt;
-    &lt;dependencies&gt;
-      &lt;dep package=&quot;orc&quot;/&gt;
-    &lt;/dependencies&gt;
-    &lt;branch repo=&quot;gstreamer&quot; module=&quot;gstreamer&quot; checkoutdir=&quot;gstreamer-b6e69ffdfb3bb21dbada8f01b488ae877f8d205c&quot; tag=&quot;b6e69ffdfb3bb21dbada8f01b488ae877f8d205c&quot;/&gt;
-  &lt;/autotools&gt;
-
-  &lt;autotools id=&quot;gst-plugins-base&quot;
-             autogen-sh=&quot;autogen.sh&quot;
-             autogenargs=&quot;--disable-examples --disable-gtk-doc&quot;&gt;
-    &lt;if condition-set=&quot;macos&quot;&gt;
-      &lt;autogenargs value=&quot;--disable-introspection&quot;/&gt;
-    &lt;/if&gt;
-    &lt;dependencies&gt;
-      &lt;dep package=&quot;gstreamer&quot;/&gt;
-    &lt;/dependencies&gt;
-    &lt;branch repo=&quot;gstreamer&quot; module=&quot;gst-plugins-base&quot; checkoutdir=&quot;gst-plugins-base-cf18fae9deb02f0867b67593f678b932f8eb931a&quot; tag=&quot;cf18fae9deb02f0867b67593f678b932f8eb931a&quot;/&gt;
-  &lt;/autotools&gt;
-
-  &lt;autotools id=&quot;gst-plugins-good&quot; autogenargs=&quot;--disable-examples --disable-soup --disable-gtk-doc&quot;&gt;
-    &lt;if condition-set=&quot;macos&quot;&gt;
-      &lt;autogenargs value=&quot;--disable-introspection&quot;/&gt;
-    &lt;/if&gt;
-    &lt;dependencies&gt;
-     &lt;dep package=&quot;libvpx&quot;/&gt;
-     &lt;dep package=&quot;gst-plugins-base&quot;/&gt;
-    &lt;/dependencies&gt;
-     &lt;branch repo=&quot;gstreamer&quot; module=&quot;gst-plugins-good&quot; checkoutdir=&quot;gst-plugins-good-567afdd4d3f2fa07fecf4c02a7eca70f7a7ef7f7&quot; tag=&quot;567afdd4d3f2fa07fecf4c02a7eca70f7a7ef7f7&quot;/&gt;
-  &lt;/autotools&gt;
-
-  &lt;autotools id=&quot;gst-plugins-bad&quot; autogenargs=&quot;--disable-examples --disable-gtk-doc --enable-openh264&quot;&gt;
-    &lt;if condition-set=&quot;macos&quot;&gt;
-      &lt;autogenargs value=&quot;--disable-introspection&quot;/&gt;
-    &lt;/if&gt;
-    &lt;dependencies&gt;
-      &lt;dep package=&quot;gst-plugins-base&quot;/&gt;
-      &lt;dep package=&quot;openh264&quot;/&gt;
-    &lt;/dependencies&gt;
-    &lt;branch repo=&quot;gstreamer&quot; module=&quot;gst-plugins-bad&quot; checkoutdir=&quot;gst-plugins-bad-a036b7ef9ffe9fe5dac4a7e46fbc3bac92921a54&quot; tag=&quot;a036b7ef9ffe9fe5dac4a7e46fbc3bac92921a54&quot;/&gt;
-  &lt;/autotools&gt;
-  
-&lt;/moduleset&gt;
</del></span></pre></div>
<a id="trunkToolsgtkpatchesgstpluginsgood0001rtpbinpipelinegetsanEOSwhenanyrtpsourcesbyespatch"></a>
<div class="addfile"><h4>Added: trunk/Tools/gtk/patches/gst-plugins-good-0001-rtpbin-pipeline-gets-an-EOS-when-any-rtpsources-byes.patch (0 => 208940)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/gtk/patches/gst-plugins-good-0001-rtpbin-pipeline-gets-an-EOS-when-any-rtpsources-byes.patch                                (rev 0)
+++ trunk/Tools/gtk/patches/gst-plugins-good-0001-rtpbin-pipeline-gets-an-EOS-when-any-rtpsources-byes.patch        2016-11-21 08:09:03 UTC (rev 208940)
</span><span class="lines">@@ -0,0 +1,156 @@
</span><ins>+From eeea2a7fe88a17b15318d5b6ae6e190b2f777030 Mon Sep 17 00:00:00 2001
+From: &quot;Alejandro G. Castro&quot; &lt;alex@igalia.com&gt;
+Date: Wed, 26 Oct 2016 13:21:29 +0200
+Subject: [PATCH] rtpbin: pipeline gets an EOS when any rtpsources byes
+
+Instead of sending EOS when a source byes we have to wait for
+all the sources to be gone, which means they already sent BYE and
+were removed from the session. We now handle the EOS in the rtcp
+loop checking the amount of sources in the session.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=773218
+---
+ gst/rtpmanager/gstrtpsession.c | 29 +++++++++++++++++++----------
+ gst/rtpmanager/rtpsession.c    |  6 +-----
+ gst/rtpmanager/rtpsession.h    |  3 +--
+ 3 files changed, 21 insertions(+), 17 deletions(-)
+
+diff --git a/gst/rtpmanager/gstrtpsession.c b/gst/rtpmanager/gstrtpsession.c
+index 3688e85..fd1f2b1 100644
+--- a/gst/rtpmanager/gstrtpsession.c
++++ b/gst/rtpmanager/gstrtpsession.c
+@@ -293,7 +293,7 @@ static GstFlowReturn gst_rtp_session_process_rtp (RTPSession * sess,
+ static GstFlowReturn gst_rtp_session_send_rtp (RTPSession * sess,
+     RTPSource * src, gpointer data, gpointer user_data);
+ static GstFlowReturn gst_rtp_session_send_rtcp (RTPSession * sess,
+-    RTPSource * src, GstBuffer * buffer, gboolean eos, gpointer user_data);
++    RTPSource * src, GstBuffer * buffer, gpointer user_data);
+ static GstFlowReturn gst_rtp_session_sync_rtcp (RTPSession * sess,
+     GstBuffer * buffer, gpointer user_data);
+ static gint gst_rtp_session_clock_rate (RTPSession * sess, guint8 payload,
+@@ -1156,6 +1156,22 @@ rtcp_thread (GstRtpSession * rtpsession)
+     GST_RTP_SESSION_UNLOCK (rtpsession);
+     rtp_session_on_timeout (session, current_time, ntpnstime, running_time);
+     GST_RTP_SESSION_LOCK (rtpsession);
++
++    if (!rtp_session_get_num_sources (session)) {
++      /* when no sources left in the session, all of the them have went
++       * BYE at some point and removed, we can send EOS to the
++       * pipeline. */
++      GstPad *rtcp_src = rtpsession-&gt;send_rtcp_src;
++
++      if (rtcp_src) {
++        gst_object_ref (rtcp_src);
++        GST_LOG_OBJECT (rtpsession, &quot;sending EOS&quot;);
++        GST_RTP_SESSION_UNLOCK (rtpsession);
++        gst_pad_push_event (rtpsession-&gt;send_rtcp_src, gst_event_new_eos ());
++        GST_RTP_SESSION_LOCK (rtpsession);
++        gst_object_unref (rtcp_src);
++      }
++    }
+   }
+   /* mark the thread as stopped now */
+   rtpsession-&gt;priv-&gt;thread_stopped = TRUE;
+@@ -1413,11 +1429,10 @@ do_rtcp_events (GstRtpSession * rtpsession, GstPad * srcpad)
+ }

+ /* called when the session manager has an RTCP packet ready for further
+- * sending. The eos flag is set when an EOS event should be sent downstream as
+- * well. */
++ * sending. */
+ static GstFlowReturn
+ gst_rtp_session_send_rtcp (RTPSession * sess, RTPSource * src,
+-    GstBuffer * buffer, gboolean eos, gpointer user_data)
++    GstBuffer * buffer, gpointer user_data)
+ {
+   GstFlowReturn result;
+   GstRtpSession *rtpsession;
+@@ -1440,11 +1455,6 @@ gst_rtp_session_send_rtcp (RTPSession * sess, RTPSource * src,
+     GST_LOG_OBJECT (rtpsession, &quot;sending RTCP&quot;);
+     result = gst_pad_push (rtcp_src, buffer);

+-    /* we have to send EOS after this packet */
+-    if (eos) {
+-      GST_LOG_OBJECT (rtpsession, &quot;sending EOS&quot;);
+-      gst_pad_push_event (rtcp_src, gst_event_new_eos ());
+-    }
+     gst_object_unref (rtcp_src);
+   } else {
+     GST_RTP_SESSION_UNLOCK (rtpsession);
+@@ -2056,7 +2066,6 @@ gst_rtp_session_event_send_rtcp_src (GstPad * pad, GstObject * parent,
+   return ret;
+ }

+-
+ static gboolean
+ gst_rtp_session_event_send_rtp_sink (GstPad * pad, GstObject * parent,
+     GstEvent * event)
+diff --git a/gst/rtpmanager/rtpsession.c b/gst/rtpmanager/rtpsession.c
+index 8b33b6b..aa8b40b 100644
+--- a/gst/rtpmanager/rtpsession.c
++++ b/gst/rtpmanager/rtpsession.c
+@@ -3263,7 +3263,6 @@ early_exit:
+ typedef struct
+ {
+   RTPSource *source;
+-  gboolean is_bye;
+   GstBuffer *buffer;
+ } ReportOutput;

+@@ -3874,7 +3873,6 @@ static void
+ generate_rtcp (const gchar * key, RTPSource * source, ReportData * data)
+ {
+   RTPSession *sess = data-&gt;sess;
+-  gboolean is_bye = FALSE;
+   ReportOutput *output;

+   /* only generate RTCP for active internal sources */
+@@ -3893,7 +3891,6 @@ generate_rtcp (const gchar * key, RTPSource * source, ReportData * data)
+   if (source-&gt;marked_bye) {
+     /* send BYE */
+     make_source_bye (sess, source, data);
+-    is_bye = TRUE;
+   } else if (!data-&gt;is_early) {
+     /* loop over all known sources and add report blocks. If we are early, we
+      * just make a minimal RTCP packet and skip this step */
+@@ -3918,7 +3915,6 @@ generate_rtcp (const gchar * key, RTPSource * source, ReportData * data)

+   output = g_slice_new (ReportOutput);
+   output-&gt;source = g_object_ref (source);
+-  output-&gt;is_bye = is_bye;
+   output-&gt;buffer = data-&gt;rtcp;
+   /* queue the RTCP packet to push later */
+   g_queue_push_tail (&amp;data-&gt;output, output);
+@@ -4098,7 +4094,7 @@ done:
+       GST_DEBUG (&quot;%p, sending RTCP packet, avg size %u, %u&quot;, &amp;sess-&gt;stats,
+           sess-&gt;stats.avg_rtcp_packet_size, packet_size);
+       result =
+-          sess-&gt;callbacks.send_rtcp (sess, source, buffer, output-&gt;is_bye,
++          sess-&gt;callbacks.send_rtcp (sess, source, buffer,
+           sess-&gt;send_rtcp_user_data);

+       RTP_SESSION_LOCK (sess);
+diff --git a/gst/rtpmanager/rtpsession.h b/gst/rtpmanager/rtpsession.h
+index 9fa9327..c25981a 100644
+--- a/gst/rtpmanager/rtpsession.h
++++ b/gst/rtpmanager/rtpsession.h
+@@ -71,7 +71,6 @@ typedef GstFlowReturn (*RTPSessionSendRTP) (RTPSession *sess, RTPSource *src, gp
+  * @sess: an #RTPSession
+  * @src: the #RTPSource
+  * @buffer: the RTCP buffer ready for sending
+- * @eos: if an EOS event should be pushed
+  * @user_data: user data specified when registering
+  *
+  * This callback will be called when @sess has @buffer ready for sending to
+@@ -80,7 +79,7 @@ typedef GstFlowReturn (*RTPSessionSendRTP) (RTPSession *sess, RTPSource *src, gp
+  * Returns: a #GstFlowReturn.
+  */
+ typedef GstFlowReturn (*RTPSessionSendRTCP) (RTPSession *sess, RTPSource *src, GstBuffer *buffer,
+-    gboolean eos, gpointer user_data);
++    gpointer user_data);

+ /**
+  * RTPSessionSyncRTCP:
+-- 
+2.10.2
+
</ins></span></pre></div>
<a id="trunkToolsgtkpatchesgstpluginsgood0002rtpbinavoidgeneratingerrorswhenrtcpmessagesarpatch"></a>
<div class="addfile"><h4>Added: trunk/Tools/gtk/patches/gst-plugins-good-0002-rtpbin-avoid-generating-errors-when-rtcp-messages-ar.patch (0 => 208940)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/gtk/patches/gst-plugins-good-0002-rtpbin-avoid-generating-errors-when-rtcp-messages-ar.patch                                (rev 0)
+++ trunk/Tools/gtk/patches/gst-plugins-good-0002-rtpbin-avoid-generating-errors-when-rtcp-messages-ar.patch        2016-11-21 08:09:03 UTC (rev 208940)
</span><span class="lines">@@ -0,0 +1,61 @@
</span><ins>+From dab6c473c3e1b2b400ee18afc70140c2f842debf Mon Sep 17 00:00:00 2001
+From: &quot;Alejandro G. Castro&quot; &lt;alex@igalia.com&gt;
+Date: Thu, 20 Oct 2016 13:14:13 +0200
+Subject: [PATCH] rtpbin: avoid generating errors when rtcp messages are empty
+ and check the queue is not empty
+
+Add a check to verify all the output buffers were empty for the
+session in a timout and log an error.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=773269
+---
+ gst/rtpmanager/rtpsession.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/gst/rtpmanager/rtpsession.c b/gst/rtpmanager/rtpsession.c
+index 75908c0..f1d9210 100644
+--- a/gst/rtpmanager/rtpsession.c
++++ b/gst/rtpmanager/rtpsession.c
+@@ -3923,6 +3923,7 @@ rtp_session_on_timeout (RTPSession * sess, GstClockTime current_time,
+   ReportData data = { GST_RTCP_BUFFER_INIT };
+   GHashTable *table_copy;
+   ReportOutput *output;
++  gboolean all_empty = FALSE;

+   g_return_val_if_fail (RTP_IS_SESSION (sess), GST_FLOW_ERROR);

+@@ -3989,6 +3990,9 @@ rtp_session_on_timeout (RTPSession * sess, GstClockTime current_time,
+   if (!is_rtcp_time (sess, current_time, &amp;data))
+     goto done;

++  /* check if all the buffers are empty afer generation */
++  all_empty = TRUE;
++
+   GST_DEBUG
+       (&quot;doing RTCP generation %u for %u sources, early %d, may suppress %d&quot;,
+       sess-&gt;generation, data.num_to_report, data.is_early, data.may_suppress);
+@@ -4036,8 +4040,8 @@ done:

+     empty_buffer = gst_buffer_get_size (buffer) == 0;

+-    if (empty_buffer)
+-      g_warning (&quot;rtpsession: Trying to send an empty RTCP packet&quot;);
++    if (!empty_buffer)
++      all_empty = FALSE;

+     if (sess-&gt;callbacks.send_rtcp &amp;&amp;
+         !empty_buffer &amp;&amp; (do_not_suppress || !data.may_suppress)) {
+@@ -4068,6 +4072,10 @@ done:
+     g_object_unref (source);
+     g_slice_free (ReportOutput, output);
+   }
++
++  if (all_empty)
++    GST_ERROR (&quot;generated empty RTCP messages for all the sources&quot;);
++
+   return result;
+ }

+-- 
+2.10.2
+
</ins></span></pre></div>
<a id="trunkToolsgtkpatchesgstpluginsgood0003rtpbinreceivebundlesupportpatch"></a>
<div class="addfile"><h4>Added: trunk/Tools/gtk/patches/gst-plugins-good-0003-rtpbin-receive-bundle-support.patch (0 => 208940)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/gtk/patches/gst-plugins-good-0003-rtpbin-receive-bundle-support.patch                                (rev 0)
+++ trunk/Tools/gtk/patches/gst-plugins-good-0003-rtpbin-receive-bundle-support.patch        2016-11-21 08:09:03 UTC (rev 208940)
</span><span class="lines">@@ -0,0 +1,1018 @@
</span><ins>+From dcd3ce9751cdef0b5ab1fa118355f92bdfe82cb3 Mon Sep 17 00:00:00 2001
+From: Philippe Normand &lt;philn@igalia.com&gt;
+Date: Wed, 16 Nov 2016 08:56:34 +0100
+Subject: [PATCH] rtpbin: receive bundle support
+
+A new signal named on-bundled-ssrc is provided and can be
+used by the application to redirect a stream to a different
+GstRtpSession or to keep the RTX stream grouped within the
+GstRtpSession of the same media type.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=772740
+---
+ docs/plugins/gst-plugins-good-plugins.signals |   8 +
+ gst/rtpmanager/gstrtpbin.c                    | 562 ++++++++++++++++++--------
+ gst/rtpmanager/gstrtpbin.h                    |   2 +
+ tests/check/Makefile.am                       |   4 +
+ tests/check/elements/.gitignore               |   1 +
+ tests/check/elements/rtpbundle.c              | 390 ++++++++++++++++++
+ tests/check/meson.build                       |   1 +
+ tests/examples/rtp/.gitignore                 |   2 +
+ tests/examples/rtp/Makefile.am                |  10 +-
+ tests/examples/rtp/client-rtpbundle.c         | 266 ++++++++++++
+ tests/examples/rtp/server-rtpbundle.c         | 179 ++++++++
+ 11 files changed, 1265 insertions(+), 160 deletions(-)
+ create mode 100644 tests/check/elements/rtpbundle.c
+ create mode 100644 tests/examples/rtp/client-rtpbundle.c
+ create mode 100644 tests/examples/rtp/server-rtpbundle.c
+
+diff --git a/docs/plugins/gst-plugins-good-plugins.signals b/docs/plugins/gst-plugins-good-plugins.signals
+index 3db17e9..44bbdda 100644
+--- a/docs/plugins/gst-plugins-good-plugins.signals
++++ b/docs/plugins/gst-plugins-good-plugins.signals
+@@ -375,6 +375,14 @@ guint  arg1
+ &lt;/SIGNAL&gt;

+ &lt;SIGNAL&gt;
++&lt;NAME&gt;GstRtpBin::on-bundled-ssrc&lt;/NAME&gt;
++&lt;RETURNS&gt;guint&lt;/RETURNS&gt;
++&lt;FLAGS&gt;l&lt;/FLAGS&gt;
++GstRtpBin *gstrtpbin
++guint  arg1
++&lt;/SIGNAL&gt;
++
++&lt;SIGNAL&gt;
+ &lt;NAME&gt;GstRtpJitterBuffer::clear-pt-map&lt;/NAME&gt;
+ &lt;RETURNS&gt;void&lt;/RETURNS&gt;
+ &lt;FLAGS&gt;la&lt;/FLAGS&gt;
+diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c
+index 648adb9..f58de01 100644
+--- a/gst/rtpmanager/gstrtpbin.c
++++ b/gst/rtpmanager/gstrtpbin.c
+@@ -53,6 +53,13 @@
+  * SSRC in the RTP packets to its own SSRC and wil forward the packets on the
+  * send_rtp_src_\%u pad after updating its internal state.
+  *
++ * #GstRtpBin can also demultiplex incoming bundled streams. The first
++ * #GstRtpSession will have a #GstRtpSsrcDemux element splitting the streams
++ * based on their SSRC and potentially dispatched to a different #GstRtpSession.
++ * Because retransmission SSRCs need to be merged with the corresponding media
++ * stream the #GstRtpBin::on-bundled-ssrc signal is emitted so that the
++ * application can find out to which session the SSRC belongs.
++ *
+  * The session manager needs the clock-rate of the payload types it is handling
+  * and will signal the #GstRtpSession::request-pt-map signal when it needs such a
+  * mapping. One can clear the cached values with the #GstRtpSession::clear-pt-map
+@@ -276,6 +283,8 @@ enum
+   SIGNAL_ON_NEW_SENDER_SSRC,
+   SIGNAL_ON_SENDER_SSRC_ACTIVE,

++  SIGNAL_ON_BUNDLED_SSRC,
++
+   LAST_SIGNAL
+ };

+@@ -362,6 +371,14 @@ static void remove_send_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session);
+ static void remove_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session);
+ static void free_client (GstRtpBinClient * client, GstRtpBin * bin);
+ static void free_stream (GstRtpBinStream * stream, GstRtpBin * bin);
++static GstRtpBinSession *create_session (GstRtpBin * rtpbin, gint id);
++static GstPad *complete_session_sink (GstRtpBin * rtpbin,
++    GstRtpBinSession * session, gboolean bundle_demuxer_needed);
++static void
++complete_session_receiver (GstRtpBin * rtpbin, GstRtpBinSession * session,
++    guint sessid);
++static GstPad *complete_session_rtcp (GstRtpBin * rtpbin,
++    GstRtpBinSession * session, guint sessid, gboolean bundle_demuxer_needed);

+ /* Manages the RTP stream for one SSRC.
+  *
+@@ -428,6 +445,12 @@ struct _GstRtpBinSession
+   gulong demux_newpad_sig;
+   gulong demux_padremoved_sig;

++  /* Bundling support */
++  GstElement *rtp_funnel;
++  GstElement *rtcp_funnel;
++  GstElement *bundle_demux;
++  gulong bundle_demux_newpad_sig;
++
+   GMutex lock;

+   /* list of GstRtpBinStream */
+@@ -629,6 +652,96 @@ ssrc_demux_pad_removed (GstElement * element, guint ssrc, GstPad * pad,
+   GST_RTP_BIN_UNLOCK (rtpbin);
+ }

++static void
++new_bundled_ssrc_pad_found (GstElement * element, guint ssrc, GstPad * pad,
++    GstRtpBinSession * session)
++{
++  GValue result = G_VALUE_INIT;
++  GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT };
++  guint session_id = 0;
++  GstRtpBinSession *target_session = NULL;
++  GstRtpBin *rtpbin = session-&gt;bin;
++  gchar *name;
++  GstPad *src_pad;
++  GstPad *recv_rtp_sink = NULL;
++  GstPad *recv_rtcp_sink = NULL;
++  GstPadLinkReturn ret;
++
++  GST_RTP_BIN_DYN_LOCK (rtpbin);
++  GST_DEBUG_OBJECT (rtpbin, &quot;new bundled SSRC pad %08x, %s:%s&quot;, ssrc,
++      GST_DEBUG_PAD_NAME (pad));
++
++  g_value_init (&amp;result, G_TYPE_UINT);
++  g_value_init (&amp;params[0], GST_TYPE_ELEMENT);
++  g_value_set_object (&amp;params[0], rtpbin);
++  g_value_init (&amp;params[1], G_TYPE_UINT);
++  g_value_set_uint (&amp;params[1], ssrc);
++
++  g_signal_emitv (params,
++      gst_rtp_bin_signals[SIGNAL_ON_BUNDLED_SSRC], 0, &amp;result);
++  g_value_unset (&amp;params[0]);
++
++  session_id = g_value_get_uint (&amp;result);
++  if (session_id == 0) {
++    target_session = session;
++  } else {
++    target_session = find_session_by_id (rtpbin, (gint) session_id);
++    if (!target_session) {
++      target_session = create_session (rtpbin, session_id);
++    }
++    if (!target_session-&gt;recv_rtp_sink) {
++      recv_rtp_sink = complete_session_sink (rtpbin, target_session, FALSE);
++    }
++
++    if (!target_session-&gt;recv_rtp_src)
++      complete_session_receiver (rtpbin, target_session, session_id);
++
++    if (!target_session-&gt;recv_rtcp_sink) {
++      recv_rtcp_sink =
++          complete_session_rtcp (rtpbin, target_session, session_id, FALSE);
++    }
++  }
++
++  GST_DEBUG_OBJECT (rtpbin, &quot;Assigning bundled ssrc %u to session %u&quot;, ssrc,
++      session_id);
++
++  if (!recv_rtp_sink) {
++    recv_rtp_sink =
++        gst_element_get_request_pad (target_session-&gt;rtp_funnel, &quot;sink_%u&quot;);
++  }
++
++  if (!recv_rtcp_sink) {
++    recv_rtcp_sink =
++        gst_element_get_request_pad (target_session-&gt;rtcp_funnel, &quot;sink_%u&quot;);
++  }
++
++  name = g_strdup_printf (&quot;src_%u&quot;, ssrc);
++  src_pad = gst_element_get_static_pad (element, name);
++  ret = gst_pad_link (src_pad, recv_rtp_sink);
++  g_free (name);
++  gst_object_unref (src_pad);
++  gst_object_unref (recv_rtp_sink);
++  if (ret != GST_PAD_LINK_OK) {
++    g_warning
++        (&quot;rtpbin: failed to link bundle demuxer to receive rtp funnel for session %u&quot;,
++        session_id);
++  }
++
++  name = g_strdup_printf (&quot;rtcp_src_%u&quot;, ssrc);
++  src_pad = gst_element_get_static_pad (element, name);
++  gst_pad_link (src_pad, recv_rtcp_sink);
++  g_free (name);
++  gst_object_unref (src_pad);
++  gst_object_unref (recv_rtcp_sink);
++  if (ret != GST_PAD_LINK_OK) {
++    g_warning
++        (&quot;rtpbin: failed to link bundle demuxer to receive rtcp sink pad for session %u&quot;,
++        session_id);
++  }
++
++  GST_RTP_BIN_DYN_UNLOCK (rtpbin);
++}
++
+ /* create a session with the given id.  Must be called with RTP_BIN_LOCK */
+ static GstRtpBinSession *
+ create_session (GstRtpBin * rtpbin, gint id)
+@@ -649,6 +762,10 @@ create_session (GstRtpBin * rtpbin, gint id)
+   sess-&gt;bin = rtpbin;
+   sess-&gt;session = session;
+   sess-&gt;demux = demux;
++
++  sess-&gt;rtp_funnel = gst_element_factory_make (&quot;funnel&quot;, NULL);
++  sess-&gt;rtcp_funnel = gst_element_factory_make (&quot;funnel&quot;, NULL);
++
+   sess-&gt;ptmap = g_hash_table_new_full (NULL, NULL, NULL,
+       (GDestroyNotify) gst_caps_unref);
+   rtpbin-&gt;sessions = g_slist_prepend (rtpbin-&gt;sessions, sess);
+@@ -696,6 +813,8 @@ create_session (GstRtpBin * rtpbin, gint id)

+   gst_bin_add (GST_BIN_CAST (rtpbin), session);
+   gst_bin_add (GST_BIN_CAST (rtpbin), demux);
++  gst_bin_add (GST_BIN_CAST (rtpbin), sess-&gt;rtp_funnel);
++  gst_bin_add (GST_BIN_CAST (rtpbin), sess-&gt;rtcp_funnel);

+   GST_OBJECT_LOCK (rtpbin);
+   target = GST_STATE_TARGET (rtpbin);
+@@ -704,6 +823,8 @@ create_session (GstRtpBin * rtpbin, gint id)
+   /* change state only to what's needed */
+   gst_element_set_state (demux, target);
+   gst_element_set_state (session, target);
++  gst_element_set_state (sess-&gt;rtp_funnel, target);
++  gst_element_set_state (sess-&gt;rtcp_funnel, target);

+   return sess;

+@@ -807,7 +928,7 @@ get_pt_map (GstRtpBinSession * session, guint pt)
+   GValue ret = { 0 };
+   GValue args[3] = { {0}, {0}, {0} };

+-  GST_DEBUG (&quot;searching pt %d in cache&quot;, pt);
++  GST_DEBUG (&quot;searching pt %u in cache&quot;, pt);

+   GST_RTP_SESSION_LOCK (session);

+@@ -820,7 +941,7 @@ get_pt_map (GstRtpBinSession * session, guint pt)

+   bin = session-&gt;bin;

+-  GST_DEBUG (&quot;emiting signal for pt %d in session %d&quot;, pt, session-&gt;id);
++  GST_DEBUG (&quot;emiting signal for pt %u in session %u&quot;, pt, session-&gt;id);

+   /* not in cache, send signal to request caps */
+   g_value_init (&amp;args[0], GST_TYPE_ELEMENT);
+@@ -856,7 +977,7 @@ get_pt_map (GstRtpBinSession * session, guint pt)
+   if (!caps)
+     goto no_caps;

+-  GST_DEBUG (&quot;caching pt %d as %&quot; GST_PTR_FORMAT, pt, caps);
++  GST_DEBUG (&quot;caching pt %u as %&quot; GST_PTR_FORMAT, pt, caps);

+   /* store in cache, take additional ref */
+   g_hash_table_insert (session-&gt;ptmap, GINT_TO_POINTER (pt),
+@@ -947,7 +1068,7 @@ gst_rtp_bin_get_session (GstRtpBin * bin, guint session_id)
+   GstElement *ret = NULL;

+   GST_RTP_BIN_LOCK (bin);
+-  GST_DEBUG_OBJECT (bin, &quot;retrieving GstRtpSession, index: %d&quot;, session_id);
++  GST_DEBUG_OBJECT (bin, &quot;retrieving GstRtpSession, index: %u&quot;, session_id);
+   session = find_session_by_id (bin, (gint) session_id);
+   if (session) {
+     ret = gst_object_ref (session-&gt;session);
+@@ -964,7 +1085,7 @@ gst_rtp_bin_get_internal_session (GstRtpBin * bin, guint session_id)
+   GstRtpBinSession *session;

+   GST_RTP_BIN_LOCK (bin);
+-  GST_DEBUG_OBJECT (bin, &quot;retrieving internal RTPSession object, index: %d&quot;,
++  GST_DEBUG_OBJECT (bin, &quot;retrieving internal RTPSession object, index: %u&quot;,
+       session_id);
+   session = find_session_by_id (bin, (gint) session_id);
+   if (session) {
+@@ -2194,6 +2315,29 @@ gst_rtp_bin_class_init (GstRtpBinClass * klass)
+           on_sender_ssrc_active), NULL, NULL, g_cclosure_marshal_generic,
+       G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);

++
++  /**
++   * GstRtpBin::on-bundled-ssrc:
++   * @rtpbin: the object which received the signal
++   * @ssrc: the bundled SSRC
++   *
++   * Notify of a new incoming bundled SSRC. If no handler is connected to the
++   * signal then the #GstRtpSession created for the recv_rtp_sink_\%u
++   * request pad will be managing this new SSRC. However if there is a handler
++   * connected then the application can decided to dispatch this new stream to
++   * another session by providing its ID as return value of the handler. This
++   * can be particularly useful to keep retransmission SSRCs grouped with the
++   * session for which they handle retransmission.
++   *
++   * Since: 1.12
++   */
++  gst_rtp_bin_signals[SIGNAL_ON_BUNDLED_SSRC] =
++      g_signal_new (&quot;on-bundled-ssrc&quot;, G_TYPE_FROM_CLASS (klass),
++      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass,
++          on_bundled_ssrc), NULL, NULL,
++      g_cclosure_marshal_generic, G_TYPE_UINT, 1, G_TYPE_UINT);
++
++
+   g_object_class_install_property (gobject_class, PROP_SDES,
+       g_param_spec_boxed (&quot;sdes&quot;, &quot;SDES&quot;,
+           &quot;The SDES items of this session&quot;,
+@@ -3021,7 +3165,7 @@ new_payload_found (GstElement * element, guint pt, GstPad * pad,

+   rtpbin = stream-&gt;bin;

+-  GST_DEBUG (&quot;new payload pad %d&quot;, pt);
++  GST_DEBUG_OBJECT (rtpbin, &quot;new payload pad %u&quot;, pt);

+   GST_RTP_BIN_SHUTDOWN_LOCK (rtpbin, shutdown);

+@@ -3078,7 +3222,7 @@ pt_map_requested (GstElement * element, guint pt, GstRtpBinSession * session)

+   rtpbin = session-&gt;bin;

+-  GST_DEBUG_OBJECT (rtpbin, &quot;payload map requested for pt %d in session %d&quot;, pt,
++  GST_DEBUG_OBJECT (rtpbin, &quot;payload map requested for pt %u in session %u&quot;, pt,
+       session-&gt;id);

+   caps = get_pt_map (session, pt);
+@@ -3099,7 +3243,7 @@ static void
+ payload_type_change (GstElement * element, guint pt, GstRtpBinSession * session)
+ {
+   GST_DEBUG_OBJECT (session-&gt;bin,
+-      &quot;emiting signal for pt type changed to %d in session %d&quot;, pt,
++      &quot;emiting signal for pt type changed to %u in session %u&quot;, pt,
+       session-&gt;id);

+   g_signal_emit (session-&gt;bin, gst_rtp_bin_signals[SIGNAL_PAYLOAD_TYPE_CHANGE],
+@@ -3246,15 +3390,42 @@ no_stream:
+   }
+ }

+-static gboolean
+-complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session)
++static void
++session_maybe_create_bundle_demuxer (GstRtpBinSession * session)
++{
++  GstRtpBin *rtpbin;
++
++  if (session-&gt;bundle_demux)
++    return;
++
++  rtpbin = session-&gt;bin;
++  if (g_signal_has_handler_pending (rtpbin,
++          gst_rtp_bin_signals[SIGNAL_ON_BUNDLED_SSRC], 0, TRUE)) {
++    GST_DEBUG_OBJECT (rtpbin, &quot;Adding a bundle SSRC demuxer to session %u&quot;,
++        session-&gt;id);
++    session-&gt;bundle_demux = gst_element_factory_make (&quot;rtpssrcdemux&quot;, NULL);
++    session-&gt;bundle_demux_newpad_sig = g_signal_connect (session-&gt;bundle_demux,
++        &quot;new-ssrc-pad&quot;, (GCallback) new_bundled_ssrc_pad_found, session);
++
++    gst_bin_add (GST_BIN_CAST (rtpbin), session-&gt;bundle_demux);
++    gst_element_sync_state_with_parent (session-&gt;bundle_demux);
++  } else {
++    GST_DEBUG_OBJECT (rtpbin,
++        &quot;No handler for the on-bundled-ssrc signal so no need for a bundle SSRC demuxer in session %u&quot;,
++        session-&gt;id);
++  }
++}
++
++static GstPad *
++complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session,
++    gboolean bundle_demuxer_needed)
+ {
+-  gchar *gname;
+   guint sessid = session-&gt;id;
+   GstPad *recv_rtp_sink;
++  GstPad *funnel_src;
+   GstElement *decoder;
+-  GstElementClass *klass;
+-  GstPadTemplate *templ;
++
++  g_assert (!session-&gt;recv_rtp_sink);

+   /* get recv_rtp pad and store */
+   session-&gt;recv_rtp_sink =
+@@ -3265,6 +3436,9 @@ complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session)
+   g_signal_connect (session-&gt;recv_rtp_sink, &quot;notify::caps&quot;,
+       (GCallback) caps_changed, session);

++  if (bundle_demuxer_needed)
++    session_maybe_create_bundle_demuxer (session);
++
+   GST_DEBUG_OBJECT (rtpbin, &quot;requesting RTP decoder&quot;);
+   decoder = session_request_element (session, SIGNAL_REQUEST_RTP_DECODER);
+   if (decoder) {
+@@ -3282,7 +3456,14 @@ complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session)
+     if (decsrc == NULL)
+       goto dec_src_failed;

+-    ret = gst_pad_link (decsrc, session-&gt;recv_rtp_sink);
++    if (session-&gt;bundle_demux) {
++      GstPad *demux_sink;
++      demux_sink = gst_element_get_static_pad (session-&gt;bundle_demux, &quot;sink&quot;);
++      ret = gst_pad_link (decsrc, demux_sink);
++      gst_object_unref (demux_sink);
++    } else {
++      ret = gst_pad_link (decsrc, session-&gt;recv_rtp_sink);
++    }
+     gst_object_unref (decsrc);

+     if (ret != GST_PAD_LINK_OK)
+@@ -3290,81 +3471,54 @@ complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session)

+   } else {
+     GST_DEBUG_OBJECT (rtpbin, &quot;no RTP decoder given&quot;);
+-    recv_rtp_sink = gst_object_ref (session-&gt;recv_rtp_sink);
++    if (session-&gt;bundle_demux) {
++      recv_rtp_sink =
++          gst_element_get_static_pad (session-&gt;bundle_demux, &quot;sink&quot;);
++    } else {
++      recv_rtp_sink =
++          gst_element_get_request_pad (session-&gt;rtp_funnel, &quot;sink_%u&quot;);
++    }
+   }

+-  GST_DEBUG_OBJECT (rtpbin, &quot;ghosting session sink pad&quot;);
+-  klass = GST_ELEMENT_GET_CLASS (rtpbin);
+-  gname = g_strdup_printf (&quot;recv_rtp_sink_%u&quot;, sessid);
+-  templ = gst_element_class_get_pad_template (klass, &quot;recv_rtp_sink_%u&quot;);
+-  session-&gt;recv_rtp_sink_ghost =
+-      gst_ghost_pad_new_from_template (gname, recv_rtp_sink, templ);
+-  gst_object_unref (recv_rtp_sink);
+-  gst_pad_set_active (session-&gt;recv_rtp_sink_ghost, TRUE);
+-  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session-&gt;recv_rtp_sink_ghost);
+-  g_free (gname);
++  funnel_src = gst_element_get_static_pad (session-&gt;rtp_funnel, &quot;src&quot;);
++  gst_pad_link (funnel_src, session-&gt;recv_rtp_sink);
++  gst_object_unref (funnel_src);

+-  return TRUE;
++  return recv_rtp_sink;

+   /* ERRORS */
+ pad_failed:
+   {
+     g_warning (&quot;rtpbin: failed to get session recv_rtp_sink pad&quot;);
+-    return FALSE;
++    return NULL;
+   }
+ dec_sink_failed:
+   {
+-    g_warning (&quot;rtpbin: failed to get decoder sink pad for session %d&quot;, sessid);
+-    return FALSE;
++    g_warning (&quot;rtpbin: failed to get decoder sink pad for session %u&quot;, sessid);
++    return NULL;
+   }
+ dec_src_failed:
+   {
+-    g_warning (&quot;rtpbin: failed to get decoder src pad for session %d&quot;, sessid);
++    g_warning (&quot;rtpbin: failed to get decoder src pad for session %u&quot;, sessid);
+     gst_object_unref (recv_rtp_sink);
+-    return FALSE;
++    return NULL;
+   }
+ dec_link_failed:
+   {
+-    g_warning (&quot;rtpbin: failed to link rtp decoder for session %d&quot;, sessid);
++    g_warning (&quot;rtpbin: failed to link rtp decoder for session %u&quot;, sessid);
+     gst_object_unref (recv_rtp_sink);
+-    return FALSE;
++    return NULL;
+   }
+ }

+-/* Create a pad for receiving RTP for the session in @name. Must be called with
+- * RTP_BIN_LOCK.
+- */
+-static GstPad *
+-create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
++static void
++complete_session_receiver (GstRtpBin * rtpbin, GstRtpBinSession * session,
++    guint sessid)
+ {
+-  guint sessid;
+   GstElement *aux;
+   GstPad *recv_rtp_src;
+-  GstRtpBinSession *session;
+-
+-  /* first get the session number */
+-  if (name == NULL || sscanf (name, &quot;recv_rtp_sink_%u&quot;, &amp;sessid) != 1)
+-    goto no_name;
+-
+-  GST_DEBUG_OBJECT (rtpbin, &quot;finding session %d&quot;, sessid);

+-  /* get or create session */
+-  session = find_session_by_id (rtpbin, sessid);
+-  if (!session) {
+-    GST_DEBUG_OBJECT (rtpbin, &quot;creating session %d&quot;, sessid);
+-    /* create session now */
+-    session = create_session (rtpbin, sessid);
+-    if (session == NULL)
+-      goto create_error;
+-  }
+-
+-  /* check if pad was requested */
+-  if (session-&gt;recv_rtp_sink_ghost != NULL)
+-    return session-&gt;recv_rtp_sink_ghost;
+-
+-  /* setup the session sink pad */
+-  if (!complete_session_sink (rtpbin, session))
+-    goto session_sink_failed;
++  g_assert (!session-&gt;recv_rtp_src);

+   session-&gt;recv_rtp_src =
+       gst_element_get_static_pad (session-&gt;session, &quot;recv_rtp_src&quot;);
+@@ -3381,7 +3535,7 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)

+     GST_DEBUG_OBJECT (rtpbin, &quot;linking AUX receiver&quot;);

+-    pname = g_strdup_printf (&quot;sink_%d&quot;, sessid);
++    pname = g_strdup_printf (&quot;sink_%u&quot;, sessid);
+     auxsink = gst_element_get_static_pad (aux, pname);
+     g_free (pname);
+     if (auxsink == NULL)
+@@ -3394,7 +3548,7 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)

+     /* this can be NULL when this AUX element is not to be linked to
+      * an SSRC demuxer */
+-    pname = g_strdup_printf (&quot;src_%d&quot;, sessid);
++    pname = g_strdup_printf (&quot;src_%u&quot;, sessid);
+     recv_rtp_src = gst_element_get_static_pad (aux, pname);
+     g_free (pname);
+   } else {
+@@ -3408,8 +3562,8 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
+     sinkdpad = gst_element_get_static_pad (session-&gt;demux, &quot;sink&quot;);
+     GST_DEBUG_OBJECT (rtpbin, &quot;linking demuxer RTP sink pad&quot;);
+     gst_pad_link_full (recv_rtp_src, sinkdpad, GST_PAD_LINK_CHECK_NOTHING);
+-    gst_object_unref (recv_rtp_src);
+     gst_object_unref (sinkdpad);
++    gst_object_unref (recv_rtp_src);

+     /* connect to the new-ssrc-pad signal of the SSRC demuxer */
+     session-&gt;demux_newpad_sig = g_signal_connect (session-&gt;demux,
+@@ -3417,6 +3571,71 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
+     session-&gt;demux_padremoved_sig = g_signal_connect (session-&gt;demux,
+         &quot;removed-ssrc-pad&quot;, (GCallback) ssrc_demux_pad_removed, session);
+   }
++
++  return;
++
++pad_failed:
++  {
++    g_warning (&quot;rtpbin: failed to get session recv_rtp_src pad&quot;);
++    return;
++  }
++aux_sink_failed:
++  {
++    g_warning (&quot;rtpbin: failed to get AUX sink pad for session %u&quot;, sessid);
++    return;
++  }
++aux_link_failed:
++  {
++    g_warning (&quot;rtpbin: failed to link AUX pad to session %u&quot;, sessid);
++    return;
++  }
++}
++
++/* Create a pad for receiving RTP for the session in @name. Must be called with
++ * RTP_BIN_LOCK.
++ */
++static GstPad *
++create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
++{
++  guint sessid;
++  GstRtpBinSession *session;
++  GstPad *recv_rtp_sink;
++
++  /* first get the session number */
++  if (name == NULL || sscanf (name, &quot;recv_rtp_sink_%u&quot;, &amp;sessid) != 1)
++    goto no_name;
++
++  GST_DEBUG_OBJECT (rtpbin, &quot;finding session %u&quot;, sessid);
++
++  /* get or create session */
++  session = find_session_by_id (rtpbin, sessid);
++  if (!session) {
++    GST_DEBUG_OBJECT (rtpbin, &quot;creating session %u&quot;, sessid);
++    /* create session now */
++    session = create_session (rtpbin, sessid);
++    if (session == NULL)
++      goto create_error;
++  }
++
++  /* check if pad was requested */
++  if (session-&gt;recv_rtp_sink_ghost != NULL)
++    return session-&gt;recv_rtp_sink_ghost;
++
++  /* setup the session sink pad */
++  recv_rtp_sink = complete_session_sink (rtpbin, session, TRUE);
++  if (!recv_rtp_sink)
++    goto session_sink_failed;
++
++
++  GST_DEBUG_OBJECT (rtpbin, &quot;ghosting session sink pad&quot;);
++  session-&gt;recv_rtp_sink_ghost =
++      gst_ghost_pad_new_from_template (name, recv_rtp_sink, templ);
++  gst_object_unref (recv_rtp_sink);
++  gst_pad_set_active (session-&gt;recv_rtp_sink_ghost, TRUE);
++  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session-&gt;recv_rtp_sink_ghost);
++
++  complete_session_receiver (rtpbin, session, sessid);
++
+   return session-&gt;recv_rtp_sink_ghost;

+   /* ERRORS */
+@@ -3435,21 +3654,6 @@ session_sink_failed:
+     /* warning already done */
+     return NULL;
+   }
+-pad_failed:
+-  {
+-    g_warning (&quot;rtpbin: failed to get session recv_rtp_src pad&quot;);
+-    return NULL;
+-  }
+-aux_sink_failed:
+-  {
+-    g_warning (&quot;rtpbin: failed to get AUX sink pad for session %d&quot;, sessid);
+-    return NULL;
+-  }
+-aux_link_failed:
+-  {
+-    g_warning (&quot;rtpbin: failed to link AUX pad to session %d&quot;, sessid);
+-    return NULL;
+-  }
+ }

+ static void
+@@ -3463,6 +3667,11 @@ remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session)
+     g_signal_handler_disconnect (session-&gt;demux, session-&gt;demux_padremoved_sig);
+     session-&gt;demux_padremoved_sig = 0;
+   }
++  if (session-&gt;bundle_demux_newpad_sig) {
++    g_signal_handler_disconnect (session-&gt;bundle_demux,
++        session-&gt;bundle_demux_newpad_sig);
++    session-&gt;bundle_demux_newpad_sig = 0;
++  }
+   if (session-&gt;recv_rtp_src) {
+     gst_object_unref (session-&gt;recv_rtp_src);
+     session-&gt;recv_rtp_src = NULL;
+@@ -3480,37 +3689,14 @@ remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session)
+   }
+ }

+-/* Create a pad for receiving RTCP for the session in @name. Must be called with
+- * RTP_BIN_LOCK.
+- */
+ static GstPad *
+-create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
+-    const gchar * name)
++complete_session_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session,
++    guint sessid, gboolean bundle_demuxer_needed)
+ {
+-  guint sessid;
+   GstElement *decoder;
+-  GstRtpBinSession *session;
+-  GstPad *sinkdpad, *decsink;
+-
+-  /* first get the session number */
+-  if (name == NULL || sscanf (name, &quot;recv_rtcp_sink_%u&quot;, &amp;sessid) != 1)
+-    goto no_name;
+-
+-  GST_DEBUG_OBJECT (rtpbin, &quot;finding session %d&quot;, sessid);
+-
+-  /* get or create the session */
+-  session = find_session_by_id (rtpbin, sessid);
+-  if (!session) {
+-    GST_DEBUG_OBJECT (rtpbin, &quot;creating session %d&quot;, sessid);
+-    /* create session now */
+-    session = create_session (rtpbin, sessid);
+-    if (session == NULL)
+-      goto create_error;
+-  }
+-
+-  /* check if pad was requested */
+-  if (session-&gt;recv_rtcp_sink_ghost != NULL)
+-    return session-&gt;recv_rtcp_sink_ghost;
++  GstPad *sinkdpad;
++  GstPad *decsink = NULL;
++  GstPad *funnel_src;

+   /* get recv_rtp pad and store */
+   GST_DEBUG_OBJECT (rtpbin, &quot;getting RTCP sink pad&quot;);
+@@ -3519,6 +3705,9 @@ create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
+   if (session-&gt;recv_rtcp_sink == NULL)
+     goto pad_failed;

++  if (bundle_demuxer_needed)
++    session_maybe_create_bundle_demuxer (session);
++
+   GST_DEBUG_OBJECT (rtpbin, &quot;getting RTCP decoder&quot;);
+   decoder = session_request_element (session, SIGNAL_REQUEST_RTCP_DECODER);
+   if (decoder) {
+@@ -3535,14 +3724,26 @@ create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
+     if (decsrc == NULL)
+       goto dec_src_failed;

+-    ret = gst_pad_link (decsrc, session-&gt;recv_rtcp_sink);
++    if (session-&gt;bundle_demux) {
++      GstPad *demux_sink;
++      demux_sink =
++          gst_element_get_static_pad (session-&gt;bundle_demux, &quot;rtcp_sink&quot;);
++      ret = gst_pad_link (decsrc, demux_sink);
++      gst_object_unref (demux_sink);
++    } else {
++      ret = gst_pad_link (decsrc, session-&gt;recv_rtcp_sink);
++    }
+     gst_object_unref (decsrc);

+     if (ret != GST_PAD_LINK_OK)
+       goto dec_link_failed;
+   } else {
+     GST_DEBUG_OBJECT (rtpbin, &quot;no RTCP decoder given&quot;);
+-    decsink = gst_object_ref (session-&gt;recv_rtcp_sink);
++    if (session-&gt;bundle_demux) {
++      decsink = gst_element_get_static_pad (session-&gt;bundle_demux, &quot;rtcp_sink&quot;);
++    } else {
++      decsink = gst_element_get_request_pad (session-&gt;rtcp_funnel, &quot;sink_%u&quot;);
++    }
+   }

+   /* get srcpad, link to SSRCDemux */
+@@ -3556,26 +3757,12 @@ create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
+   gst_pad_link_full (session-&gt;sync_src, sinkdpad, GST_PAD_LINK_CHECK_NOTHING);
+   gst_object_unref (sinkdpad);

+-  session-&gt;recv_rtcp_sink_ghost =
+-      gst_ghost_pad_new_from_template (name, decsink, templ);
+-  gst_object_unref (decsink);
+-  gst_pad_set_active (session-&gt;recv_rtcp_sink_ghost, TRUE);
+-  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin),
+-      session-&gt;recv_rtcp_sink_ghost);
++  funnel_src = gst_element_get_static_pad (session-&gt;rtcp_funnel, &quot;src&quot;);
++  gst_pad_link (funnel_src, session-&gt;recv_rtcp_sink);
++  gst_object_unref (funnel_src);

+-  return session-&gt;recv_rtcp_sink_ghost;
++  return decsink;

+-  /* ERRORS */
+-no_name:
+-  {
+-    g_warning (&quot;rtpbin: invalid name given&quot;);
+-    return NULL;
+-  }
+-create_error:
+-  {
+-    /* create_session already warned */
+-    return NULL;
+-  }
+ pad_failed:
+   {
+     g_warning (&quot;rtpbin: failed to get session rtcp_sink pad&quot;);
+@@ -3583,25 +3770,82 @@ pad_failed:
+   }
+ dec_sink_failed:
+   {
+-    g_warning (&quot;rtpbin: failed to get decoder sink pad for session %d&quot;, sessid);
++    g_warning (&quot;rtpbin: failed to get decoder sink pad for session %u&quot;, sessid);
+     return NULL;
+   }
+ dec_src_failed:
+   {
+-    g_warning (&quot;rtpbin: failed to get decoder src pad for session %d&quot;, sessid);
+-    gst_object_unref (decsink);
+-    return NULL;
++    g_warning (&quot;rtpbin: failed to get decoder src pad for session %u&quot;, sessid);
++    goto cleanup;
+   }
+ dec_link_failed:
+   {
+-    g_warning (&quot;rtpbin: failed to link rtcp decoder for session %d&quot;, sessid);
+-    gst_object_unref (decsink);
+-    return NULL;
++    g_warning (&quot;rtpbin: failed to link rtcp decoder for session %u&quot;, sessid);
++    goto cleanup;
+   }
+ src_pad_failed:
+   {
+     g_warning (&quot;rtpbin: failed to get session sync_src pad&quot;);
+-    gst_object_unref (decsink);
++  }
++
++cleanup:
++  gst_object_unref (decsink);
++  return NULL;
++}
++
++/* Create a pad for receiving RTCP for the session in @name. Must be called with
++ * RTP_BIN_LOCK.
++ */
++static GstPad *
++create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
++    const gchar * name)
++{
++  guint sessid;
++  GstRtpBinSession *session;
++  GstPad *decsink = NULL;
++
++  /* first get the session number */
++  if (name == NULL || sscanf (name, &quot;recv_rtcp_sink_%u&quot;, &amp;sessid) != 1)
++    goto no_name;
++
++  GST_DEBUG_OBJECT (rtpbin, &quot;finding session %u&quot;, sessid);
++
++  /* get or create the session */
++  session = find_session_by_id (rtpbin, sessid);
++  if (!session) {
++    GST_DEBUG_OBJECT (rtpbin, &quot;creating session %u&quot;, sessid);
++    /* create session now */
++    session = create_session (rtpbin, sessid);
++    if (session == NULL)
++      goto create_error;
++  }
++
++  /* check if pad was requested */
++  if (session-&gt;recv_rtcp_sink_ghost != NULL)
++    return session-&gt;recv_rtcp_sink_ghost;
++
++  decsink = complete_session_rtcp (rtpbin, session, sessid, TRUE);
++  if (!decsink)
++    goto create_error;
++
++  session-&gt;recv_rtcp_sink_ghost =
++      gst_ghost_pad_new_from_template (name, decsink, templ);
++  gst_object_unref (decsink);
++  gst_pad_set_active (session-&gt;recv_rtcp_sink_ghost, TRUE);
++  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin),
++      session-&gt;recv_rtcp_sink_ghost);
++
++  return session-&gt;recv_rtcp_sink_ghost;
++
++  /* ERRORS */
++no_name:
++  {
++    g_warning (&quot;rtpbin: invalid name given&quot;);
++    return NULL;
++  }
++create_error:
++  {
++    /* create_session already warned */
+     return NULL;
+   }
+ }
+@@ -3651,7 +3895,7 @@ complete_session_src (GstRtpBin * rtpbin, GstRtpBinSession * session)
+     GstPadLinkReturn ret;

+     GST_DEBUG_OBJECT (rtpbin, &quot;linking RTP encoder&quot;);
+-    ename = g_strdup_printf (&quot;rtp_src_%d&quot;, sessid);
++    ename = g_strdup_printf (&quot;rtp_src_%u&quot;, sessid);
+     encsrc = gst_element_get_static_pad (encoder, ename);
+     g_free (ename);

+@@ -3660,7 +3904,7 @@ complete_session_src (GstRtpBin * rtpbin, GstRtpBinSession * session)

+     send_rtp_src = encsrc;

+-    ename = g_strdup_printf (&quot;rtp_sink_%d&quot;, sessid);
++    ename = g_strdup_printf (&quot;rtp_sink_%u&quot;, sessid);
+     encsink = gst_element_get_static_pad (encoder, ename);
+     g_free (ename);
+     if (encsink == NULL)
+@@ -3694,23 +3938,23 @@ complete_session_src (GstRtpBin * rtpbin, GstRtpBinSession * session)
+   /* ERRORS */
+ no_srcpad:
+   {
+-    g_warning (&quot;rtpbin: failed to get rtp source pad for session %d&quot;, sessid);
++    g_warning (&quot;rtpbin: failed to get rtp source pad for session %u&quot;, sessid);
+     return FALSE;
+   }
+ enc_src_failed:
+   {
+-    g_warning (&quot;rtpbin: failed to get encoder src pad for session %d&quot;, sessid);
++    g_warning (&quot;rtpbin: failed to get encoder src pad for session %u&quot;, sessid);
+     return FALSE;
+   }
+ enc_sink_failed:
+   {
+-    g_warning (&quot;rtpbin: failed to get encoder sink pad for session %d&quot;, sessid);
++    g_warning (&quot;rtpbin: failed to get encoder sink pad for session %u&quot;, sessid);
+     gst_object_unref (send_rtp_src);
+     return FALSE;
+   }
+ enc_link_failed:
+   {
+-    g_warning (&quot;rtpbin: failed to link rtp encoder for session %d&quot;, sessid);
++    g_warning (&quot;rtpbin: failed to link rtp encoder for session %u&quot;, sessid);
+     gst_object_unref (send_rtp_src);
+     return FALSE;
+   }
+@@ -3772,22 +4016,22 @@ create_error:
+   }
+ existing_session:
+   {
+-    g_warning (&quot;rtpbin: session %d is already a sender&quot;, sessid);
++    g_warning (&quot;rtpbin: session %u is already a sender&quot;, sessid);
+     return FALSE;
+   }
+ pad_failed:
+   {
+-    g_warning (&quot;rtpbin: failed to get session pad for session %d&quot;, sessid);
++    g_warning (&quot;rtpbin: failed to get session pad for session %u&quot;, sessid);
+     return FALSE;
+   }
+ aux_link_failed:
+   {
+-    g_warning (&quot;rtpbin: failed to link AUX for session %d&quot;, sessid);
++    g_warning (&quot;rtpbin: failed to link AUX for session %u&quot;, sessid);
+     return FALSE;
+   }
+ session_src_failed:
+   {
+-    g_warning (&quot;rtpbin: failed to complete AUX for session %d&quot;, sessid);
++    g_warning (&quot;rtpbin: failed to complete AUX for session %u&quot;, sessid);
+     return FALSE;
+   }
+ }
+@@ -3847,7 +4091,7 @@ create_send_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
+     if (!setup_aux_sender (rtpbin, session, aux))
+       goto aux_session_failed;

+-    pname = g_strdup_printf (&quot;sink_%d&quot;, sessid);
++    pname = g_strdup_printf (&quot;sink_%u&quot;, sessid);
+     send_rtp_sink = gst_element_get_static_pad (aux, pname);
+     g_free (pname);

+@@ -3887,27 +4131,27 @@ create_error:
+   }
+ existing_session:
+   {
+-    g_warning (&quot;rtpbin: session %d is already in use&quot;, sessid);
++    g_warning (&quot;rtpbin: session %u is already in use&quot;, sessid);
+     return NULL;
+   }
+ aux_session_failed:
+   {
+-    g_warning (&quot;rtpbin: failed to get AUX sink pad for session %d&quot;, sessid);
++    g_warning (&quot;rtpbin: failed to get AUX sink pad for session %u&quot;, sessid);
+     return NULL;
+   }
+ aux_sink_failed:
+   {
+-    g_warning (&quot;rtpbin: failed to get AUX sink pad for session %d&quot;, sessid);
++    g_warning (&quot;rtpbin: failed to get AUX sink pad for session %u&quot;, sessid);
+     return NULL;
+   }
+ pad_failed:
+   {
+-    g_warning (&quot;rtpbin: failed to get session pad for session %d&quot;, sessid);
++    g_warning (&quot;rtpbin: failed to get session pad for session %u&quot;, sessid);
+     return NULL;
+   }
+ session_src_failed:
+   {
+-    g_warning (&quot;rtpbin: failed to setup source pads for session %d&quot;, sessid);
++    g_warning (&quot;rtpbin: failed to setup source pads for session %u&quot;, sessid);
+     return NULL;
+   }
+ }
+@@ -3978,13 +4222,13 @@ create_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)

+     GST_DEBUG_OBJECT (rtpbin, &quot;linking RTCP encoder&quot;);

+-    ename = g_strdup_printf (&quot;rtcp_src_%d&quot;, sessid);
++    ename = g_strdup_printf (&quot;rtcp_src_%u&quot;, sessid);
+     encsrc = gst_element_get_static_pad (encoder, ename);
+     g_free (ename);
+     if (encsrc == NULL)
+       goto enc_src_failed;

+-    ename = g_strdup_printf (&quot;rtcp_sink_%d&quot;, sessid);
++    ename = g_strdup_printf (&quot;rtcp_sink_%u&quot;, sessid);
+     encsink = gst_element_get_static_pad (encoder, ename);
+     g_free (ename);
+     if (encsink == NULL)
+@@ -4021,23 +4265,23 @@ no_session:
+   }
+ pad_failed:
+   {
+-    g_warning (&quot;rtpbin: failed to get rtcp pad for session %d&quot;, sessid);
++    g_warning (&quot;rtpbin: failed to get rtcp pad for session %u&quot;, sessid);
+     return NULL;
+   }
+ enc_src_failed:
+   {
+-    g_warning (&quot;rtpbin: failed to get encoder src pad for session %d&quot;, sessid);
++    g_warning (&quot;rtpbin: failed to get encoder src pad for session %u&quot;, sessid);
+     return NULL;
+   }
+ enc_sink_failed:
+   {
+-    g_warning (&quot;rtpbin: failed to get encoder sink pad for session %d&quot;, sessid);
++    g_warning (&quot;rtpbin: failed to get encoder sink pad for session %u&quot;, sessid);
+     gst_object_unref (encsrc);
+     return NULL;
+   }
+ enc_link_failed:
+   {
+-    g_warning (&quot;rtpbin: failed to link rtcp encoder for session %d&quot;, sessid);
++    g_warning (&quot;rtpbin: failed to link rtcp encoder for session %u&quot;, sessid);
+     gst_object_unref (encsrc);
+     return NULL;
+   }
+diff --git a/gst/rtpmanager/gstrtpbin.h b/gst/rtpmanager/gstrtpbin.h
+index fb13a47..384b76d 100644
+--- a/gst/rtpmanager/gstrtpbin.h
++++ b/gst/rtpmanager/gstrtpbin.h
+@@ -127,6 +127,8 @@ struct _GstRtpBinClass {

+   void     (*on_new_sender_ssrc)      (GstRtpBin *rtpbin, guint session, guint32 ssrc);
+   void     (*on_sender_ssrc_active)   (GstRtpBin *rtpbin, guint session, guint32 ssrc);
++
++  guint    (*on_bundled_ssrc)         (GstRtpBin *rtpbin, guint ssrc);
+ };

+ GType gst_rtp_bin_get_type (void);
</ins></span></pre>
</div>
</div>

</body>
</html>