using Gee; using Xmpp; using Xmpp.Xep; public class Xmpp.Xep.JingleRtp.PayloadType { public const string NAME = "payload-type"; public uint8 id { get; set; } public string? name { get; set; } public uint8 channels { get; set; default = 1; } public uint32 clockrate { get; set; } public uint32 maxptime { get; set; } public uint32 ptime { get; set; } public Map parameters = new HashMap(); public Gee.List rtcp_fbs = new ArrayList(); public static PayloadType parse(StanzaNode node) { PayloadType payloadType = new PayloadType(); payloadType.channels = (uint8) node.get_attribute_uint("channels", payloadType.channels); payloadType.clockrate = node.get_attribute_uint("clockrate"); payloadType.id = (uint8) node.get_attribute_uint("id"); payloadType.maxptime = node.get_attribute_uint("maxptime"); payloadType.name = node.get_attribute("name"); payloadType.ptime = node.get_attribute_uint("ptime"); foreach (StanzaNode parameter in node.get_subnodes("parameter")) { payloadType.parameters[parameter.get_attribute("name")] = parameter.get_attribute("value"); } foreach (StanzaNode subnode in node.get_subnodes(RtcpFeedback.NAME, RtcpFeedback.NS_URI)) { payloadType.rtcp_fbs.add(RtcpFeedback.parse(subnode)); } return payloadType; } public StanzaNode to_xml() { StanzaNode node = new StanzaNode.build(NAME, NS_URI) .put_attribute("id", id.to_string()); if (channels != 1) node.put_attribute("channels", channels.to_string()); if (clockrate != 0) node.put_attribute("clockrate", clockrate.to_string()); if (maxptime != 0) node.put_attribute("maxptime", maxptime.to_string()); if (name != null) node.put_attribute("name", name); if (ptime != 0) node.put_attribute("ptime", ptime.to_string()); foreach (string parameter in parameters.keys) { node.put_node(new StanzaNode.build("parameter", NS_URI) .put_attribute("name", parameter) .put_attribute("value", parameters[parameter])); } foreach (RtcpFeedback rtcp_fb in rtcp_fbs) { node.put_node(rtcp_fb.to_xml()); } return node; } public PayloadType clone() { PayloadType clone = new PayloadType(); clone.id = id; clone.name = name; clone.channels = channels; clone.clockrate = clockrate; clone.maxptime = maxptime; clone.ptime = ptime; clone.parameters.set_all(parameters); clone.rtcp_fbs.add_all(rtcp_fbs); return clone; } public static bool equals_func(PayloadType a, PayloadType b) { bool simple = a.id == b.id && a.name == b.name && a.channels == b.channels && a.clockrate == b.clockrate && a.maxptime == b.maxptime && a.ptime == b.ptime && a.parameters.size == b.parameters.size && a.rtcp_fbs.size == b.rtcp_fbs.size; if (!simple) return false; foreach (string key in a.parameters.keys) { if (!b.parameters.has_key(key)) return false; if (a.parameters[key] != b.parameters[key]) return false; } foreach (RtcpFeedback fb in a.rtcp_fbs) { if (!b.rtcp_fbs.any_match((it) => it.type_ == fb.type_ && it.subtype == fb.subtype)) return false; } return true; } public static uint hash_func(PayloadType payload_type) { return payload_type.to_xml().to_string().hash(); } } public class Xmpp.Xep.JingleRtp.RtcpFeedback { public const string NS_URI = "urn:xmpp:jingle:apps:rtp:rtcp-fb:0"; public const string NAME = "rtcp-fb"; public string type_ { get; private set; } public string? subtype { get; private set; } public RtcpFeedback(string type, string? subtype = null) { this.type_ = type; this.subtype = subtype; } public static RtcpFeedback parse(StanzaNode node) { return new RtcpFeedback(node.get_attribute("type"), node.get_attribute("subtype")); } public StanzaNode to_xml() { StanzaNode node = new StanzaNode.build(NAME, NS_URI) .add_self_xmlns() .put_attribute("type", type_); if (subtype != null) node.put_attribute("subtype", subtype); return node; } }