Dateien nach „slixmpp/plugins/xep_0167“ hochladen

This commit is contained in:
apprenticius 2024-12-27 12:02:42 +00:00
parent 8abc9e4ab2
commit ca6a3ce241
3 changed files with 306 additions and 0 deletions

View File

@ -0,0 +1,11 @@
# slixmpp: The Slick XMPP Library
# Copyright (C) 2020 Emmanuel Gil Peyrot
# This file is part of slixmpp.
# See the file LICENSE for copying permission.
from slixmpp.plugins.base import register_plugin
from slixmpp.plugins.xep_0167.stanza import Description, PayloadType, RtcpMux, Encryption, Bandwidth, Parameter, Crypto #, RtcpFB --> xep_0293
from slixmpp.plugins.xep_0167.rtp import XEP_0167
register_plugin(XEP_0167)

View File

@ -0,0 +1,150 @@
# slixmpp: The Slick XMPP Library
# Copyright (C) 2020 Emmanuel Gil Peyrot
# This file is part of slixmpp.
# See the file LICENSE for copying permission.
import logging
from typing import Iterable, Tuple, Optional
from slixmpp import JID, Iq
from slixmpp.plugins import BasePlugin
from slixmpp.xmlstream import register_stanza_plugin
from slixmpp.xmlstream.handler import Callback
from slixmpp.xmlstream.matcher import StanzaPath
from slixmpp.plugins.xep_0166 import Jingle, Content
from slixmpp.plugins.xep_0167 import stanza, Description, PayloadType, RtcpMux, Encryption, Bandwidth, Parameter, Crypto#, RtcpFB --> xep_0293
import re
log = logging.getLogger(__name__)
class XEP_0167(BasePlugin):
name = 'xep_0167'
description = 'XEP-0167: Jingle'
dependencies = set(['xep_0166'])
stanza = stanza
def plugin_init(self):
register_stanza_plugin(Iq,Jingle)
register_stanza_plugin(Jingle,Content,True)
register_stanza_plugin(Content,Description)
register_stanza_plugin(Description,PayloadType,True)
register_stanza_plugin(Description,RtcpMux)
register_stanza_plugin(Description,Encryption)
register_stanza_plugin(Description,Bandwidth)
register_stanza_plugin(Description,RtcpMux)
register_stanza_plugin(PayloadType,Parameter,True)
# register_stanza_plugin(PayloadType,RtcpFB) --> xep_0293
register_stanza_plugin(Encryption,Crypto)
self.xmpp.register_handler(
Callback('Rtp Jingle Description',
StanzaPath('iq/jingle/content/description'),
self._handle_content_description))
# def session_bind(self, jid):
# pass
# def plugin_end(self):
# pass
#######################################################################
def _handle_content_description(self, message):
self.xmpp.event('jingle_content_description', message['jingle']['content']['description'])
def make_description(self,sdp,media):
m = re.search(r'^m='+media+' +(\d+) +([\w/]+)([ \d]*)\r$',sdp,re.M)
if m:
description = Description()
description['media'] = media
# if self.xmpp['xep_0294']:
# hdrexts = self.xmpp['xep_0294'].make_hdrexts(sdp)
# for hdrext in hdrexts:
# description.append(hdrext)
if m.group(3):
for id in m.group(3).split():
iter = re.finditer(r'^a=rtpmap:'+id+' +([\w\-.]+)(?:/(\d+)(?:/(\S+))?)?\r$',sdp,re.M)
m = re.search(r'^a=ptime:(\S+)\r$',sdp,re.M)
ptime = None
if m:
ptime = m.group(1)
m = re.search(r'^a=maxptime:(\S+)\r$',sdp,re.M)
maxptime = None
if m:
maxptime = m.group(1)
for m in iter:
payload = PayloadType()
payload['id'] = id
payload['name'] = m.group(1)
if m.group(2):
payload['clockrate'] = m.group(2)
if m.group(3):
payload['channels'] = m.group(3)
if ptime:
payload['ptime'] = ptime
if maxptime:
payload['maxptime'] = maxptime
m1 = re.search(r'^a=fmtp:'+id+' *(.*)\r$',sdp,re.M)
if m1:
for line in m1.groups():
m2 = re.findall(r' *; *([^=;\r]+(?:=[^; \r]+)?)',f';{line}')
if m2:
for p in m2:
if p:
parameter = Parameter()
s = p.split('=')
if len(s)>1:
parameter['name'] = s[0]
parameter['value'] = s[1]
else:
parameter['value'] = s[0]
payload.append(parameter)
if self.xmpp['xep_0293']:
ret = self.xmpp['xep_0293'].make_rtcpfb(sdp,id)
for rtcpfb in ret:
payload.append(rtcpfb)
description.append(payload)
m = re.search(r'^a=crypto:(\d+) +(\S+) +(\S+) +(\S+)\r$',sdp,re.M)
if m:
encryption = Encryption()
crypto = Crypto()
crypto['tag'] = m.group(1)
crypto['crypto-suite'] = m.group(2)
crypto['key-params'] = m.group(3)
crypto['session-params'] = m.group(4)
encryption.append(crypto)
description.append(encryption)
if self.xmpp['xep_0293']:
ret = self.xmpp['xep_0293'].make_rtcpfb(sdp)
for rtcpfb in ret:
payload.append(rtcpfb)
if self.xmpp['xep_0294']:
hdrexts = self.xmpp['xep_0294'].make_hdrexts(sdp)
for hdrext in hdrexts:
description.append(hdrext)
hdrextallowmixed = self.xmpp['xep_0294'].make_extmapallowmixed(sdp)
if hdrextallowmixed!=None:
description.append(hdrextallowmixed)
if self.xmpp['xep_0339']:
ret = self.xmpp['xep_0339'].make_ssrcgroup(sdp)
if ret:
description.append(ret[0])
for source in ret[1]:
description.append(source)
else:
source = self.xmpp['xep_0339'].make_source(sdp)
if source:
description.append(source)
# hier müsste noch geprüft werden, ob \w+ in "a=group:BUNDLE X Y" vorhkommt.
m = re.search(r'^a=mid: *\w+\r$',sdp,re.M)
if m:
rtcpmux = RtcpMux()
description.append(rtcpmux)
return description
return None

View File

@ -0,0 +1,145 @@
# slixmpp: The Slick XMPP Library
# Copyright (C) 2020 Emmanuel Gil Peyrot
# This file is part of slixmpp.
# See the file LICENSE for copying permission.
from slixmpp.xmlstream import ElementBase
class Description(ElementBase):
name = 'description'
namespace = 'urn:xmpp:jingle:apps:rtp:1'
plugin_attrib = 'description'
interfaces = {'media','ssrc'}
def getSDP(self,port = None, cline = None):
ret = "\r\nm=%s %s " % (self['media'],port or '0')
if port==None:
ret += "UDP/"
if self.parent().get_plugin(name='ice-transport',check=True):
if self.parent()['ice-transport'].get_plugin(name='fingerprint',check=True):
ret += "TLS/RTP/SAVPF"
else:
ret += "TLS/RTP/SAVPF"
elif self.parent().get_plugin(name='raw-transport',check=True):
if self.parent()['raw-transport'].get_plugin(name='fingerprint',check=True):
ret += "TLS/RTP/SAVPF"
else:
ret += "RTP/AVP"
for rtcpfb in self['rtcp-fbs']: # Ist das überflüssig?
ret += rtcpfb.getSDP() or ''
tmp = ''
ptime_max = -1
maxptime_max = -1
if self['maxptime']:
maxptime_max = max(maxptime_max,int(self['maxptime']))
for payload in self['payload-types']:
ret += ' '+payload['id']
if payload['ptime']:
ptime_max = max(ptime_max,int(payload['ptime']))
if payload['maxptime']:
maxptime_max = max(maxptime_max,int(payload['maxptime']))
tmp += payload.getSDP()
if cline:
ret += cline
ret += tmp
if ptime_max>-1:
ret += "\r\na=ptime:%s" % (ptime_max)
if maxptime_max>-1:
ret += "\r\na=maxptime:%s" % (maxptime_max)
if self.get_plugin(name='hdrexts',check=True):
# ret += "\r\na=sendrecv"
for hdrext in self['hdrexts']:
ret += hdrext.getSDP() or ''
if self.get_plugin(name='extmap-allow-mixed',check=True):
ret += "\r\na=extmap-allow-mixed"
if self.get_plugin(name='ssrc-group',check=True):
ret += self['ssrc-group'].getSDP() or ''
for source in self['sources']:
ret += source.getSDP()
if self.get_plugin(name='encryption',check=True):
ret += self['encryption'].getSDP() or ''
return ret
class PayloadType(ElementBase):
name = 'payload-type'
namespace = 'urn:xmpp:jingle:apps:rtp:1'
plugin_attrib = 'payload-type'
interfaces = {'channels','clockrate','id','maxptime','name','ptime'}
plugin_multi_attrib = 'payload-types'
def getSDP(self):
ret = "\r\na=rtpmap:%s " % self['id']
# name optional in jingle if one of the standard payload ids required in sdp
# standard payload ids: https://en.m.wikipedia.org/wiki/RTP_payload_formats
if self['name']:
ret += "%s" % (self['name'])
if self['clockrate']:
ret += "/%s" % (self['clockrate'])
if self['channels']:
ret += "/%s" % (self['channels'])
# ptime, maxptime are not really usefull
if self.get_plugin(name='parameters',check=True):
ret += "\r\na=fmtp:%s " % (self['id'])
tmp = ''
for parameter in self['parameters']:
tmp += ';'+parameter.getSDP()
ret += tmp[1:]
for rtcpfb in self['rtcp-fbs']: # Ist das überflüssig?
ret += rtcpfb.getSDP(self['id']) or ''
return ret
class RtcpMux(ElementBase):
name = 'rtcp-mux'
namespace = 'urn:xmpp:jingle:apps:rtp:1'
plugin_attrib = 'rtcp-mux'
interfaces = {}
def getSDP(self):
return '\r\na=rtcp-mux'
class Encryption(ElementBase):
name = 'encryption'
namespace = 'urn:xmpp:jingle:apps:rtp:1'
plugin_attrib = 'encryption'
interfaces = {'required'}
def getSDP(self):
if self.get_plugin(name='crypto',check=True):
return self['crypto'].getSDP()
return None
class Crypto(ElementBase):
name = 'crypto'
namespace = 'urn:xmpp:jingle:apps:rtp:1'
plugin_attrib = 'crypto'
interfaces = {'crypto-suite','key-params','session-params','tag'}
def getSDP(self):
return "\r\na=crypto:%s %s %s %s" % (self['tag'],self['crypto-suite'],self['key-params'],self['session-params'])
class Bandwidth(ElementBase):
name = 'bandwidth'
namespace = 'urn:xmpp:jingle:apps:rtp:1'
plugin_attrib = 'bandwidth'
interfaces = {'type'}
class Parameter(ElementBase):
name = 'parameter'
namespace = 'urn:xmpp:jingle:apps:rtp:1'
plugin_attrib = 'parameter'
interfaces = {'name','value'}
plugin_multi_attrib = 'parameters'
def getSDP(self):
if self['name']:
return "%s=%s" % (self['name'],self['value'])
return "%s" % (self['value'])
#class RtcpFB(ElementBase): --> xep_0293
# name = 'rtcp-fb'
# namespace = 'urn:xmpp:jingle:apps:rtp:rtcp-fb:0'
# plugin_attrib = 'rtcp-fb'
# interfaces = {'subtype','type'}
#
# def getSDP(self):
# return self['type']