use of eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo in project Conversations by siacs.
the class RtpContentMap method modifiedCredentials.
public RtpContentMap modifiedCredentials(IceUdpTransportInfo.Credentials credentials, final IceUdpTransportInfo.Setup setup) {
final ImmutableMap.Builder<String, DescriptionTransport> contentMapBuilder = new ImmutableMap.Builder<>();
for (final Map.Entry<String, DescriptionTransport> content : contents.entrySet()) {
final RtpDescription rtpDescription = content.getValue().description;
IceUdpTransportInfo transportInfo = content.getValue().transport;
final IceUdpTransportInfo modifiedTransportInfo = transportInfo.modifyCredentials(credentials, setup);
contentMapBuilder.put(content.getKey(), new DescriptionTransport(rtpDescription, modifiedTransportInfo));
}
return new RtpContentMap(this.group, contentMapBuilder.build());
}
use of eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo in project Conversations by siacs.
the class SessionDescription method of.
public static SessionDescription of(final RtpContentMap contentMap) {
final SessionDescriptionBuilder sessionDescriptionBuilder = new SessionDescriptionBuilder();
final ArrayListMultimap<String, String> attributeMap = ArrayListMultimap.create();
final ImmutableList.Builder<Media> mediaListBuilder = new ImmutableList.Builder<>();
final Group group = contentMap.group;
if (group != null) {
final String semantics = group.getSemantics();
checkNoWhitespace(semantics, "group semantics value must not contain any whitespace");
attributeMap.put("group", group.getSemantics() + " " + Joiner.on(' ').join(group.getIdentificationTags()));
}
attributeMap.put("msid-semantic", " WMS my-media-stream");
for (final Map.Entry<String, RtpContentMap.DescriptionTransport> entry : contentMap.contents.entrySet()) {
final String name = entry.getKey();
RtpContentMap.DescriptionTransport descriptionTransport = entry.getValue();
RtpDescription description = descriptionTransport.description;
IceUdpTransportInfo transport = descriptionTransport.transport;
final ArrayListMultimap<String, String> mediaAttributes = ArrayListMultimap.create();
final String ufrag = transport.getAttribute("ufrag");
final String pwd = transport.getAttribute("pwd");
if (Strings.isNullOrEmpty(ufrag)) {
throw new IllegalArgumentException("Transport element is missing required ufrag attribute");
}
checkNoWhitespace(ufrag, "ufrag value must not contain any whitespaces");
mediaAttributes.put("ice-ufrag", ufrag);
if (Strings.isNullOrEmpty(pwd)) {
throw new IllegalArgumentException("Transport element is missing required pwd attribute");
}
checkNoWhitespace(pwd, "pwd value must not contain any whitespaces");
mediaAttributes.put("ice-pwd", pwd);
mediaAttributes.put("ice-options", HARDCODED_ICE_OPTIONS);
final IceUdpTransportInfo.Fingerprint fingerprint = transport.getFingerprint();
if (fingerprint != null) {
mediaAttributes.put("fingerprint", fingerprint.getHash() + " " + fingerprint.getContent());
final IceUdpTransportInfo.Setup setup = fingerprint.getSetup();
if (setup != null) {
mediaAttributes.put("setup", setup.toString().toLowerCase(Locale.ROOT));
}
}
final ImmutableList.Builder<Integer> formatBuilder = new ImmutableList.Builder<>();
for (RtpDescription.PayloadType payloadType : description.getPayloadTypes()) {
final String id = payloadType.getId();
if (Strings.isNullOrEmpty(id)) {
throw new IllegalArgumentException("Payload type is missing id");
}
if (!isInt(id)) {
throw new IllegalArgumentException("Payload id is not numeric");
}
formatBuilder.add(payloadType.getIntId());
mediaAttributes.put("rtpmap", payloadType.toSdpAttribute());
final List<RtpDescription.Parameter> parameters = payloadType.getParameters();
if (parameters.size() == 1) {
mediaAttributes.put("fmtp", RtpDescription.Parameter.toSdpString(id, parameters.get(0)));
} else if (parameters.size() > 0) {
mediaAttributes.put("fmtp", RtpDescription.Parameter.toSdpString(id, parameters));
}
for (RtpDescription.FeedbackNegotiation feedbackNegotiation : payloadType.getFeedbackNegotiations()) {
final String type = feedbackNegotiation.getType();
final String subtype = feedbackNegotiation.getSubType();
if (Strings.isNullOrEmpty(type)) {
throw new IllegalArgumentException("a feedback for payload-type " + id + " negotiation is missing type");
}
checkNoWhitespace(type, "feedback negotiation type must not contain whitespace");
mediaAttributes.put("rtcp-fb", id + " " + type + (Strings.isNullOrEmpty(subtype) ? "" : " " + subtype));
}
for (RtpDescription.FeedbackNegotiationTrrInt feedbackNegotiationTrrInt : payloadType.feedbackNegotiationTrrInts()) {
mediaAttributes.put("rtcp-fb", id + " trr-int " + feedbackNegotiationTrrInt.getValue());
}
}
for (RtpDescription.FeedbackNegotiation feedbackNegotiation : description.getFeedbackNegotiations()) {
final String type = feedbackNegotiation.getType();
final String subtype = feedbackNegotiation.getSubType();
if (Strings.isNullOrEmpty(type)) {
throw new IllegalArgumentException("a feedback negotiation is missing type");
}
checkNoWhitespace(type, "feedback negotiation type must not contain whitespace");
mediaAttributes.put("rtcp-fb", "* " + type + (Strings.isNullOrEmpty(subtype) ? "" : " " + subtype));
}
for (final RtpDescription.FeedbackNegotiationTrrInt feedbackNegotiationTrrInt : description.feedbackNegotiationTrrInts()) {
mediaAttributes.put("rtcp-fb", "* trr-int " + feedbackNegotiationTrrInt.getValue());
}
for (final RtpDescription.RtpHeaderExtension extension : description.getHeaderExtensions()) {
final String id = extension.getId();
final String uri = extension.getUri();
if (Strings.isNullOrEmpty(id)) {
throw new IllegalArgumentException("A header extension is missing id");
}
checkNoWhitespace(id, "header extension id must not contain whitespace");
if (Strings.isNullOrEmpty(uri)) {
throw new IllegalArgumentException("A header extension is missing uri");
}
checkNoWhitespace(uri, "feedback negotiation uri must not contain whitespace");
mediaAttributes.put("extmap", id + " " + uri);
}
if (description.hasChild("extmap-allow-mixed", Namespace.JINGLE_RTP_HEADER_EXTENSIONS)) {
mediaAttributes.put("extmap-allow-mixed", "");
}
for (final RtpDescription.SourceGroup sourceGroup : description.getSourceGroups()) {
final String semantics = sourceGroup.getSemantics();
final List<String> groups = sourceGroup.getSsrcs();
if (Strings.isNullOrEmpty(semantics)) {
throw new IllegalArgumentException("A SSRC group is missing semantics attribute");
}
checkNoWhitespace(semantics, "source group semantics must not contain whitespace");
if (groups.size() == 0) {
throw new IllegalArgumentException("A SSRC group is missing SSRC ids");
}
mediaAttributes.put("ssrc-group", String.format("%s %s", semantics, Joiner.on(' ').join(groups)));
}
for (final RtpDescription.Source source : description.getSources()) {
for (final RtpDescription.Source.Parameter parameter : source.getParameters()) {
final String id = source.getSsrcId();
final String parameterName = parameter.getParameterName();
final String parameterValue = parameter.getParameterValue();
if (Strings.isNullOrEmpty(id)) {
throw new IllegalArgumentException("A source specific media attribute is missing the id");
}
checkNoWhitespace(id, "A source specific media attributes must not contain whitespaces");
if (Strings.isNullOrEmpty(parameterName)) {
throw new IllegalArgumentException("A source specific media attribute is missing its name");
}
if (Strings.isNullOrEmpty(parameterValue)) {
throw new IllegalArgumentException("A source specific media attribute is missing its value");
}
mediaAttributes.put("ssrc", id + " " + parameterName + ":" + parameterValue);
}
}
mediaAttributes.put("mid", name);
// random additional attributes
mediaAttributes.put("rtcp", "9 IN IP4 0.0.0.0");
mediaAttributes.put("sendrecv", "");
if (description.hasChild("rtcp-mux", Namespace.JINGLE_APPS_RTP)) {
mediaAttributes.put("rtcp-mux", "");
}
final MediaBuilder mediaBuilder = new MediaBuilder();
mediaBuilder.setMedia(description.getMedia().toString().toLowerCase(Locale.ROOT));
mediaBuilder.setConnectionData(HARDCODED_CONNECTION);
mediaBuilder.setPort(HARDCODED_MEDIA_PORT);
mediaBuilder.setProtocol(HARDCODED_MEDIA_PROTOCOL);
mediaBuilder.setAttributes(mediaAttributes);
mediaBuilder.setFormats(formatBuilder.build());
mediaListBuilder.add(mediaBuilder.createMedia());
}
sessionDescriptionBuilder.setVersion(0);
sessionDescriptionBuilder.setName("-");
sessionDescriptionBuilder.setMedia(mediaListBuilder.build());
sessionDescriptionBuilder.setAttributes(attributeMap);
return sessionDescriptionBuilder.createSessionDescription();
}
use of eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo in project Conversations by siacs.
the class JingleRtpConnection method processCandidate.
private void processCandidate(final Map.Entry<String, RtpContentMap.DescriptionTransport> content) {
final RtpContentMap rtpContentMap = getRemoteContentMap();
final List<String> indices = toIdentificationTags(rtpContentMap);
// aka content name
final String sdpMid = content.getKey();
final IceUdpTransportInfo transport = content.getValue().transport;
final IceUdpTransportInfo.Credentials credentials = transport.getCredentials();
for (final IceUdpTransportInfo.Candidate candidate : transport.getCandidates()) {
final String sdp;
try {
sdp = candidate.toSdpAttribute(credentials.ufrag);
} catch (final IllegalArgumentException e) {
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": ignoring invalid ICE candidate " + e.getMessage());
continue;
}
final int mLineIndex = indices.indexOf(sdpMid);
if (mLineIndex < 0) {
Log.w(Config.LOGTAG, "mLineIndex not found for " + sdpMid + ". available indices " + indices);
}
final IceCandidate iceCandidate = new IceCandidate(sdpMid, mLineIndex, sdp);
Log.d(Config.LOGTAG, "received candidate: " + iceCandidate);
this.webRTCWrapper.addIceCandidate(iceCandidate);
}
}
use of eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo in project Conversations by siacs.
the class AxolotlService method decrypt.
private OmemoVerifiedPayload<IceUdpTransportInfo> decrypt(final OmemoVerifiedIceUdpTransportInfo verifiedIceUdpTransportInfo, final Jid from, ImmutableList.Builder<ListenableFuture<XmppAxolotlSession>> pepVerificationFutures) throws CryptoFailedException {
final IceUdpTransportInfo transportInfo = new IceUdpTransportInfo();
transportInfo.setAttributes(verifiedIceUdpTransportInfo.getAttributes());
final OmemoVerification omemoVerification = new OmemoVerification();
for (final Element child : verifiedIceUdpTransportInfo.getChildren()) {
if ("fingerprint".equals(child.getName()) && Namespace.OMEMO_DTLS_SRTP_VERIFICATION.equals(child.getNamespace())) {
final Element fingerprint = new Element("fingerprint", Namespace.JINGLE_APPS_DTLS);
fingerprint.setAttribute("setup", child.getAttribute("setup"));
fingerprint.setAttribute("hash", child.getAttribute("hash"));
final Element encrypted = child.findChildEnsureSingle(XmppAxolotlMessage.CONTAINERTAG, AxolotlService.PEP_PREFIX);
final XmppAxolotlMessage xmppAxolotlMessage = XmppAxolotlMessage.fromElement(encrypted, from.asBareJid());
final XmppAxolotlSession session = getReceivingSession(xmppAxolotlMessage);
final XmppAxolotlMessage.XmppAxolotlPlaintextMessage plaintext = xmppAxolotlMessage.decrypt(session, getOwnDeviceId());
final Integer preKeyId = session.getPreKeyIdAndReset();
if (preKeyId != null) {
postponedSessions.add(session);
}
if (session.isFresh()) {
pepVerificationFutures.add(putFreshSession(session));
} else if (Config.REQUIRE_RTP_VERIFICATION) {
pepVerificationFutures.add(Futures.immediateFuture(session));
}
fingerprint.setContent(plaintext.getPlaintext());
omemoVerification.setDeviceId(session.getRemoteAddress().getDeviceId());
omemoVerification.setSessionFingerprint(plaintext.getFingerprint());
transportInfo.addChild(fingerprint);
} else {
transportInfo.addChild(child);
}
}
return new OmemoVerifiedPayload<>(omemoVerification, transportInfo);
}
use of eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo in project Conversations by siacs.
the class AxolotlService method decrypt.
public ListenableFuture<OmemoVerifiedPayload<RtpContentMap>> decrypt(OmemoVerifiedRtpContentMap omemoVerifiedRtpContentMap, final Jid from) {
final ImmutableMap.Builder<String, RtpContentMap.DescriptionTransport> descriptionTransportBuilder = new ImmutableMap.Builder<>();
final OmemoVerification omemoVerification = new OmemoVerification();
final ImmutableList.Builder<ListenableFuture<XmppAxolotlSession>> pepVerificationFutures = new ImmutableList.Builder<>();
for (final Map.Entry<String, RtpContentMap.DescriptionTransport> content : omemoVerifiedRtpContentMap.contents.entrySet()) {
final RtpContentMap.DescriptionTransport descriptionTransport = content.getValue();
final OmemoVerifiedPayload<IceUdpTransportInfo> decryptedTransport;
try {
decryptedTransport = decrypt((OmemoVerifiedIceUdpTransportInfo) descriptionTransport.transport, from, pepVerificationFutures);
} catch (CryptoFailedException e) {
return Futures.immediateFailedFuture(e);
}
omemoVerification.setOrEnsureEqual(decryptedTransport);
descriptionTransportBuilder.put(content.getKey(), new RtpContentMap.DescriptionTransport(descriptionTransport.description, decryptedTransport.payload));
}
processPostponed();
final ImmutableList<ListenableFuture<XmppAxolotlSession>> sessionFutures = pepVerificationFutures.build();
return Futures.transform(Futures.allAsList(sessionFutures), sessions -> {
if (Config.REQUIRE_RTP_VERIFICATION) {
for (XmppAxolotlSession session : sessions) {
requireVerification(session);
}
}
return new OmemoVerifiedPayload<>(omemoVerification, new RtpContentMap(omemoVerifiedRtpContentMap.group, descriptionTransportBuilder.build()));
}, MoreExecutors.directExecutor());
}
Aggregations