Skip to content

Commit 0a3d1fd

Browse files
committed
add support for RTCConfiguration.alwaysNegotiateDataChannels
which always negotiates datachannels and puts them first in the SDP. Spec: w3c/webrtc-extensions#242
1 parent d73af99 commit 0a3d1fd

File tree

3 files changed

+56
-7
lines changed

3 files changed

+56
-7
lines changed

src/aiortc/rtcconfiguration.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,6 @@ class RTCConfiguration:
6464

6565
bundlePolicy: RTCBundlePolicy = RTCBundlePolicy.BALANCED
6666
"The media-bundling policy to use when gathering ICE candidates."
67+
68+
alwaysNegotiateDataChannels: bool = False
69+
"Whether to always negotiate data channels in the SDP."

src/aiortc/rtcpeerconnection.py

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,22 @@ def get_media_section(
702702
def next_mline_index() -> int:
703703
return len(description.media)
704704

705+
def add_datachannel_section() -> None:
706+
self.__sctp_mline_index = next_mline_index()
707+
description.media.append(
708+
create_media_description_for_sctp(
709+
self.__sctp, legacy=self._sctpLegacySdp, mid=allocate_mid(mids)
710+
)
711+
)
712+
713+
# JSEP specifies that it should only be added after audio/video m-sections
714+
# but the `alwaysNegotiateDataChannels` option overrides that:
715+
# https://w3c.github.io/webrtc-extensions/#always-negotiating-datachannels
716+
# This implies that it will be used for negotiating BUNDLE.
717+
if not self.__sctp and self.__configuration.alwaysNegotiateDataChannels:
718+
self.__createSctpTransport()
719+
add_datachannel_section()
720+
705721
for transceiver in filter(
706722
lambda x: x.mid is None and not x.stopped, self.__transceivers
707723
):
@@ -714,13 +730,12 @@ def next_mline_index() -> int:
714730
mid=allocate_mid(mids),
715731
)
716732
)
717-
if self.__sctp and self.__sctp.mid is None:
718-
self.__sctp_mline_index = next_mline_index()
719-
description.media.append(
720-
create_media_description_for_sctp(
721-
self.__sctp, legacy=self._sctpLegacySdp, mid=allocate_mid(mids)
722-
)
723-
)
733+
if (
734+
self.__sctp
735+
and self.__sctp.mid is None
736+
and not self.__configuration.alwaysNegotiateDataChannels
737+
):
738+
add_datachannel_section()
724739

725740
bundle = sdp.GroupDescription(semantic="BUNDLE", items=[])
726741
for media in description.media:

tests/test_rtcpeerconnection.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5471,3 +5471,34 @@ async def test_bundlepolicy_transports_max_bundle(self) -> None:
54715471
transceiver1.receiver.transport.transport.iceGatherer.getLocalParameters(),
54725472
pc.sctp.transport.transport.iceGatherer.getLocalParameters(),
54735473
)
5474+
5475+
@asynctest
5476+
async def test_always_negotiate_datachannels(self) -> None:
5477+
pc = RTCPeerConnection(RTCConfiguration(alwaysNegotiateDataChannels=True))
5478+
pc.addTransceiver("audio")
5479+
offer = await pc.createOffer()
5480+
parsed = SessionDescription.parse(offer.sdp)
5481+
self.assertEqual(len(parsed.media), 2)
5482+
self.assertEqual("application", parsed.media[0].kind)
5483+
self.assertEqual("audio", parsed.media[1].kind)
5484+
5485+
@asynctest
5486+
async def test_always_negotiate_datachannels_subsequent(self) -> None:
5487+
pc1 = RTCPeerConnection(RTCConfiguration(alwaysNegotiateDataChannels=True))
5488+
pc2 = RTCPeerConnection()
5489+
5490+
pc1.addTransceiver("audio")
5491+
await pc1.setLocalDescription()
5492+
await pc2.setRemoteDescription(pc1.localDescription)
5493+
await pc2.setLocalDescription()
5494+
await pc1.setRemoteDescription(pc2.localDescription)
5495+
5496+
for pc in [pc1, pc2]:
5497+
parsed = SessionDescription.parse(pc.localDescription.sdp)
5498+
self.assertEqual(len(parsed.media), 2)
5499+
5500+
pc.createDataChannel("test")
5501+
offer = await pc.createOffer()
5502+
parsed = SessionDescription.parse(offer.sdp)
5503+
self.assertEqual(len(parsed.media), 2)
5504+

0 commit comments

Comments
 (0)