Python implementation of WebRTC and ORTC for real-time peer-to-peer communication
87
WebRTC configuration objects, RTP parameters, codec capabilities, and session description handling for connection setup and media negotiation.
Configuration options for RTCPeerConnection setup.
class RTCConfiguration:
"""Configuration for RTCPeerConnection."""
def __init__(self, iceServers=None, bundlePolicy=RTCBundlePolicy.BALANCED):
"""
Create RTCConfiguration.
Parameters:
- iceServers (list, optional): List of RTCIceServer objects
- bundlePolicy (RTCBundlePolicy, optional): Media bundling policy (default: BALANCED)
"""
@property
def iceServers(self) -> list:
"""List of RTCIceServer objects for STUN/TURN servers"""
@property
def bundlePolicy(self) -> RTCBundlePolicy:
"""Media bundling policy"""STUN/TURN server configuration for ICE connectivity.
class RTCIceServer:
"""STUN/TURN server configuration."""
def __init__(self, urls, username=None, credential=None, credentialType="password"):
"""
Create ICE server configuration.
Parameters:
- urls (str or list): STUN/TURN server URLs
- username (str, optional): Authentication username (required for TURN)
- credential (str, optional): Authentication credential (required for TURN)
- credentialType (str, optional): Credential type (default: "password")
"""
@property
def urls(self) -> list:
"""List of server URLs"""
@property
def username(self) -> str:
"""Authentication username"""
@property
def credential(self) -> str:
"""Authentication credential"""
@property
def credentialType(self) -> str:
"""Credential type"""Media bundling policy options for ICE candidate gathering.
class RTCBundlePolicy:
"""Media bundling policy enumeration."""
BALANCED = "balanced" # Gather ICE candidates per media type
MAX_COMPAT = "max-compat" # Gather ICE candidates per track
MAX_BUNDLE = "max-bundle" # Gather ICE candidates for single track onlyConfiguration objects for RTP media negotiation.
class RTCRtpParameters:
"""RTP connection parameters."""
@property
def codecs(self) -> list:
"""List of RTCRtpCodecParameters"""
@property
def headerExtensions(self) -> list:
"""List of RTCRtpHeaderExtensionParameters"""
@property
def rtcp(self) -> RTCRtcpParameters:
"""RTCP parameters"""
class RTCRtpCapabilities:
"""RTP codec and extension capabilities."""
@property
def codecs(self) -> list:
"""List of RTCRtpCodecCapability objects"""
@property
def headerExtensions(self) -> list:
"""List of RTCRtpHeaderExtensionCapability objects"""
class RTCRtpCodecCapability:
"""Individual codec capability."""
@property
def mimeType(self) -> str:
"""Codec MIME type (e.g., "audio/opus", "video/VP8")"""
@property
def clockRate(self) -> int:
"""Codec clock rate in Hz"""
@property
def channels(self) -> int:
"""Number of audio channels (None for video)"""
@property
def parameters(self) -> dict:
"""Codec-specific parameters"""
class RTCRtpCodecParameters:
"""Codec configuration parameters."""
@property
def mimeType(self) -> str:
"""Codec MIME type"""
@property
def clockRate(self) -> int:
"""Codec clock rate"""
@property
def channels(self) -> int:
"""Number of channels"""
@property
def payloadType(self) -> int:
"""RTP payload type (96-127 for dynamic types)"""
@property
def parameters(self) -> dict:
"""Codec parameters"""
class RTCRtpHeaderExtensionCapability:
"""Header extension capability."""
@property
def uri(self) -> str:
"""Extension URI"""
class RTCRtpHeaderExtensionParameters:
"""Header extension parameters."""
@property
def uri(self) -> str:
"""Extension URI"""
@property
def id(self) -> int:
"""Extension ID (1-14)"""
class RTCRtcpParameters:
"""RTCP configuration parameters."""
@property
def cname(self) -> str:
"""Canonical name for RTCP"""
@property
def reducedSize(self) -> bool:
"""Whether to use reduced-size RTCP"""SDP session description handling for offer/answer exchange.
class RTCSessionDescription:
"""Session Description Protocol representation."""
def __init__(self, sdp: str, type: str):
"""
Create session description.
Parameters:
- sdp (str): SDP string content
- type (str): Description type ("offer", "answer", "pranswer", "rollback")
"""
@property
def sdp(self) -> str:
"""SDP string content"""
@property
def type(self) -> str:
"""Description type"""import aiortc
# Create basic configuration with STUN server
config = aiortc.RTCConfiguration(
iceServers=[
aiortc.RTCIceServer("stun:stun.l.google.com:19302")
]
)
# Create peer connection with configuration
pc = aiortc.RTCPeerConnection(configuration=config)
print(f"Bundle policy: {config.bundlePolicy}")
print(f"ICE servers: {[server.urls for server in config.iceServers]}")# Multiple STUN/TURN servers with authentication
config = aiortc.RTCConfiguration(
iceServers=[
# Public STUN servers
aiortc.RTCIceServer([
"stun:stun.l.google.com:19302",
"stun:stun1.l.google.com:19302"
]),
# TURN server with authentication
aiortc.RTCIceServer(
urls="turn:turnserver.example.com:3478",
username="myusername",
credential="mypassword"
),
# TURN server with TCP transport
aiortc.RTCIceServer(
urls="turn:turnserver.example.com:443?transport=tcp",
username="myusername",
credential="mypassword"
)
],
bundlePolicy=aiortc.RTCBundlePolicy.MAX_BUNDLE
)
pc = aiortc.RTCPeerConnection(configuration=config)
# Access configuration details
for i, server in enumerate(config.iceServers):
print(f"Server {i+1}:")
print(f" URLs: {server.urls}")
print(f" Username: {server.username}")
print(f" Credential type: {server.credentialType}")# Different bundle policies
configs = {
"balanced": aiortc.RTCConfiguration(
bundlePolicy=aiortc.RTCBundlePolicy.BALANCED
),
"max_compat": aiortc.RTCConfiguration(
bundlePolicy=aiortc.RTCBundlePolicy.MAX_COMPAT
),
"max_bundle": aiortc.RTCConfiguration(
bundlePolicy=aiortc.RTCBundlePolicy.MAX_BUNDLE
)
}
for policy_name, config in configs.items():
print(f"{policy_name}: {config.bundlePolicy}")
# Different bundle policies affect ICE candidate gathering
pc = aiortc.RTCPeerConnection(configuration=config)
# ... use peer connection# Get available codec capabilities
audio_caps = aiortc.RTCRtpSender.getCapabilities("audio")
video_caps = aiortc.RTCRtpSender.getCapabilities("video")
print("Audio Codecs:")
for codec in audio_caps.codecs:
print(f" {codec.mimeType}")
print(f" Clock rate: {codec.clockRate} Hz")
print(f" Channels: {codec.channels}")
print(f" Parameters: {codec.parameters}")
print("\nVideo Codecs:")
for codec in video_caps.codecs:
print(f" {codec.mimeType}")
print(f" Clock rate: {codec.clockRate} Hz")
print(f" Parameters: {codec.parameters}")
print("\nAudio Header Extensions:")
for ext in audio_caps.headerExtensions:
print(f" {ext.uri}")
print("\nVideo Header Extensions:")
for ext in video_caps.headerExtensions:
print(f" {ext.uri}")async def handle_session_descriptions():
pc1 = aiortc.RTCPeerConnection()
pc2 = aiortc.RTCPeerConnection()
# PC1 creates offer
offer = await pc1.createOffer()
print(f"Offer type: {offer.type}")
print(f"Offer SDP length: {len(offer.sdp)} characters")
# Set local description on PC1
await pc1.setLocalDescription(offer)
print(f"PC1 signaling state: {pc1.signalingState}")
# Send offer to PC2 and set as remote description
await pc2.setRemoteDescription(offer)
print(f"PC2 signaling state: {pc2.signalingState}")
# PC2 creates answer
answer = await pc2.createAnswer()
print(f"Answer type: {answer.type}")
# Set local description on PC2
await pc2.setLocalDescription(answer)
print(f"PC2 signaling state: {pc2.signalingState}")
# Send answer to PC1 and set as remote description
await pc1.setRemoteDescription(answer)
print(f"PC1 signaling state: {pc1.signalingState}")
# Access session descriptions
print(f"PC1 local: {pc1.localDescription.type}")
print(f"PC1 remote: {pc1.remoteDescription.type}")
print(f"PC2 local: {pc2.localDescription.type}")
print(f"PC2 remote: {pc2.remoteDescription.type}")async def custom_rtp_parameters():
pc = aiortc.RTCPeerConnection()
# Add transceiver to get RTP parameters
transceiver = pc.addTransceiver("video")
# Get current parameters (after negotiation)
# Note: This would typically be done after setLocalDescription
try:
# Create a mock RTP parameters object for demonstration
class MockRtpParameters:
def __init__(self):
self.codecs = []
self.headerExtensions = []
self.rtcp = None
# In real usage, you'd get this from the transceiver after negotiation
params = MockRtpParameters()
# Example of how you might inspect codec parameters
video_caps = aiortc.RTCRtpSender.getCapabilities("video")
print("Available video codecs:")
for codec in video_caps.codecs:
print(f" {codec.mimeType} - Clock: {codec.clockRate}")
except Exception as e:
print(f"Could not get RTP parameters: {e}")def validate_configuration():
"""Validate RTCConfiguration settings."""
# Test various configuration scenarios
test_configs = [
# Valid configuration
{
"name": "Valid STUN only",
"config": aiortc.RTCConfiguration(
iceServers=[aiortc.RTCIceServer("stun:stun.l.google.com:19302")]
)
},
# Valid TURN configuration
{
"name": "Valid TURN with auth",
"config": aiortc.RTCConfiguration(
iceServers=[aiortc.RTCIceServer(
"turn:turnserver.example.com:3478",
username="user",
credential="pass"
)]
)
},
# No ICE servers (valid, will use defaults)
{
"name": "No ICE servers",
"config": aiortc.RTCConfiguration()
}
]
for test in test_configs:
try:
pc = aiortc.RTCPeerConnection(configuration=test["config"])
print(f"✓ {test['name']}: Valid")
# Access configuration properties
config = test["config"]
print(f" Bundle policy: {config.bundlePolicy}")
print(f" ICE servers: {len(config.iceServers) if config.iceServers else 0}")
except Exception as e:
print(f"✗ {test['name']}: Invalid - {e}")async def dynamic_configuration():
"""Demonstrate dynamic configuration scenarios."""
# Start with basic configuration
initial_config = aiortc.RTCConfiguration(
iceServers=[aiortc.RTCIceServer("stun:stun.l.google.com:19302")]
)
pc = aiortc.RTCPeerConnection(configuration=initial_config)
print("Initial configuration:")
print(f" ICE servers: {len(pc.configuration.iceServers)}")
print(f" Bundle policy: {pc.configuration.bundlePolicy}")
# Note: RTCPeerConnection doesn't support configuration changes after creation
# You would need to create a new peer connection with updated configuration
updated_config = aiortc.RTCConfiguration(
iceServers=[
aiortc.RTCIceServer("stun:stun.l.google.com:19302"),
aiortc.RTCIceServer(
"turn:turnserver.example.com:3478",
username="newuser",
credential="newpass"
)
],
bundlePolicy=aiortc.RTCBundlePolicy.MAX_BUNDLE
)
# Create new peer connection with updated config
new_pc = aiortc.RTCPeerConnection(configuration=updated_config)
print("Updated configuration:")
print(f" ICE servers: {len(new_pc.configuration.iceServers)}")
print(f" Bundle policy: {new_pc.configuration.bundlePolicy}")
# Clean up original connection
await pc.close()Install with Tessl CLI
npx tessl i tessl/pypi-aiortcdocs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10