Mercurial > libervia-backend
comparison libervia/backend/plugins/plugin_xep_0167/mapping.py @ 4121:b2709504586a
plugin XEP-0167: mapping adjustments:
- use `9` as port placeholder
- add `a=ice-options:trickle` to indicate that ICE candidates may be sent after SDP
- moved senders mapping at media level
- fix `rtpmap` channel setting
- don't overwrite existing `fingerprint` data
rel 424
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 03 Oct 2023 15:25:52 +0200 |
parents | 23fa52acf72c |
children | e11b13418ba6 |
comparison
equal
deleted
inserted
replaced
4120:832a7bdb3aea | 4121:b2709504586a |
---|---|
42 else: | 42 else: |
43 return "a=recvonly" | 43 return "a=recvonly" |
44 | 44 |
45 | 45 |
46 def generate_sdp_from_session( | 46 def generate_sdp_from_session( |
47 session: dict, local: bool = False, port: int = 9999 | 47 session: dict, local: bool = False, port: int = 9 |
48 ) -> str: | 48 ) -> str: |
49 """Generate an SDP string from session data. | 49 """Generate an SDP string from session data. |
50 | 50 |
51 @param session: A dictionary containing the session data. It should have the | 51 @param session: A dictionary containing the session data. It should have the |
52 following structure: | 52 following structure: |
76 and not needed in backend, except for debugging purpose. | 76 and not needed in backend, except for debugging purpose. |
77 @param port: The preferred port for communications. | 77 @param port: The preferred port for communications. |
78 | 78 |
79 @return: The generated SDP string. | 79 @return: The generated SDP string. |
80 """ | 80 """ |
81 contents = session["contents"] | |
81 sdp_lines = ["v=0"] | 82 sdp_lines = ["v=0"] |
82 | 83 |
83 # Add originator (o=) line after the version (v=) line | 84 # Add originator (o=) line after the version (v=) line |
84 username = base64.b64encode(session["local_jid"].full().encode()).decode() | 85 username = base64.b64encode(session["local_jid"].full().encode()).decode() |
85 session_id = "1" # Increment this for each session | 86 session_id = "1" # Increment this for each session |
99 | 100 |
100 # stream direction | 101 # stream direction |
101 all_senders = {c["senders"] for c in session["contents"].values()} | 102 all_senders = {c["senders"] for c in session["contents"].values()} |
102 # if we don't have a common senders for all contents, we set them at media level | 103 # if we don't have a common senders for all contents, we set them at media level |
103 senders = all_senders.pop() if len(all_senders) == 1 else None | 104 senders = all_senders.pop() if len(all_senders) == 1 else None |
104 if senders is not None: | |
105 sdp_lines.append(senders_to_sdp(senders, session)) | |
106 | 105 |
107 sdp_lines.append("a=msid-semantic:WMS *") | 106 sdp_lines.append("a=msid-semantic:WMS *") |
107 sdp_lines.append("a=ice-options:trickle") | |
108 | 108 |
109 host.trigger.point( | 109 host.trigger.point( |
110 "XEP-0167_generate_sdp_session", | 110 "XEP-0167_generate_sdp_session", |
111 session, | 111 session, |
112 local, | 112 local, |
113 sdp_lines, | 113 sdp_lines, |
114 triggers_no_cancel=True | 114 triggers_no_cancel=True |
115 ) | 115 ) |
116 | 116 |
117 contents = session["contents"] | |
118 for content_name, content_data in contents.items(): | 117 for content_name, content_data in contents.items(): |
119 app_data_key = "local_data" if local else "peer_data" | 118 app_data_key = "local_data" if local else "peer_data" |
120 application_data = content_data["application_data"] | 119 application_data = content_data["application_data"] |
121 media_data = application_data[app_data_key] | 120 media_data = application_data[app_data_key] |
122 media = application_data["media"] | 121 media = application_data["media"] |
129 sdp_lines.append(m_line) | 128 sdp_lines.append(m_line) |
130 | 129 |
131 sdp_lines.append(f"c={network_type} {address_type} {connection_address}") | 130 sdp_lines.append(f"c={network_type} {address_type} {connection_address}") |
132 | 131 |
133 sdp_lines.append(f"a=mid:{content_name}") | 132 sdp_lines.append(f"a=mid:{content_name}") |
133 if senders is not None: | |
134 sdp_lines.append(senders_to_sdp(senders, session)) | |
134 | 135 |
135 # stream direction | 136 # stream direction |
136 if senders is None: | 137 if senders is None: |
137 sdp_lines.append(senders_to_sdp(content_data["senders"], session)) | 138 sdp_lines.append(senders_to_sdp(content_data["senders"], session)) |
139 | |
138 | 140 |
139 # Generate a= lines for rtpmap and fmtp | 141 # Generate a= lines for rtpmap and fmtp |
140 for pt_id, pt in payload_types.items(): | 142 for pt_id, pt in payload_types.items(): |
141 name = pt["name"] | 143 name = pt["name"] |
142 clockrate = pt.get("clockrate", "") | 144 clockrate = pt.get("clockrate", "") |
143 sdp_lines.append(f"a=rtpmap:{pt_id} {name}/{clockrate}") | 145 |
146 # Check if "channels" is in pt and append it to the line | |
147 channels = pt.get("channels") | |
148 if channels: | |
149 sdp_lines.append(f"a=rtpmap:{pt_id} {name}/{clockrate}/{channels}") | |
150 else: | |
151 sdp_lines.append(f"a=rtpmap:{pt_id} {name}/{clockrate}") | |
144 | 152 |
145 if "ptime" in pt: | 153 if "ptime" in pt: |
146 sdp_lines.append(f"a=ptime:{pt['ptime']}") | 154 sdp_lines.append(f"a=ptime:{pt['ptime']}") |
147 | 155 |
148 if "parameters" in pt: | 156 if "parameters" in pt: |
381 | 389 |
382 elif attribute == "fingerprint": | 390 elif attribute == "fingerprint": |
383 algorithm, fingerprint = parts[0], parts[1] | 391 algorithm, fingerprint = parts[0], parts[1] |
384 fingerprint_data = {"hash": algorithm, "fingerprint": fingerprint} | 392 fingerprint_data = {"hash": algorithm, "fingerprint": fingerprint} |
385 if transport_data is not None: | 393 if transport_data is not None: |
386 transport_data["fingerprint"] = fingerprint_data | 394 transport_data.setdefault("fingerprint", {}).update( |
395 fingerprint_data | |
396 ) | |
387 elif attribute == "setup": | 397 elif attribute == "setup": |
388 assert transport_data is not None | 398 assert transport_data is not None |
389 setup = parts[0] | 399 setup = parts[0] |
390 transport_data.setdefault("fingerprint", {})["setup"] = setup | 400 transport_data.setdefault("fingerprint", {})["setup"] = setup |
391 | 401 |
427 # to handle session data at media level)) | 437 # to handle session data at media level)) |
428 for key in [k for k in call_data if k.startswith("_")]: | 438 for key in [k for k in call_data if k.startswith("_")]: |
429 log.debug(f"cleaning remaining private data {key!r}") | 439 log.debug(f"cleaning remaining private data {key!r}") |
430 del call_data[key] | 440 del call_data[key] |
431 | 441 |
442 # FIXME: is this really useful? | |
432 # ICE candidates may only be specified for the first media, this | 443 # ICE candidates may only be specified for the first media, this |
433 # duplicate the candidate for the other in this case | 444 # duplicate the candidate for the other in this case |
434 all_media = {k:v for k,v in call_data.items() if k in ("audio", "video")} | 445 all_media = {k:v for k,v in call_data.items() if k in ("audio", "video")} |
435 if len(all_media) > 1 and not all( | 446 if len(all_media) > 1 and not all( |
436 "candidates" in c["transport_data"] for c in all_media.values() | 447 "candidates" in c["transport_data"] for c in all_media.values() |