Detailed changes
@@ -9,146 +9,164 @@ import java.util.List;
import java.util.Map;
public class Presences {
- private final Hashtable<String, Presence> presences = new Hashtable<>();
-
- public List<Presence> getPresences() {
- synchronized (this.presences) {
- return new ArrayList<>(this.presences.values());
- }
- }
-
- public Presence get(String resource) {
- synchronized (this.presences) {
- return this.presences.get(resource);
- }
- }
-
- public void updatePresence(String resource, Presence presence) {
- synchronized (this.presences) {
- this.presences.put(resource, presence);
- }
- }
-
- public void removePresence(String resource) {
- synchronized (this.presences) {
- this.presences.remove(resource);
- }
- }
-
- public void clearPresences() {
- synchronized (this.presences) {
- this.presences.clear();
- }
- }
-
- public Presence.Status getShownStatus() {
- Presence.Status status = Presence.Status.OFFLINE;
- synchronized (this.presences) {
- for(Presence p : presences.values()) {
- if (p.getStatus() == Presence.Status.DND) {
- return p.getStatus();
- } else if (p.getStatus().compareTo(status) < 0){
- status = p.getStatus();
- }
- }
- }
- return status;
- }
-
- public int size() {
- synchronized (this.presences) {
- return presences.size();
- }
- }
-
- public String[] toResourceArray() {
- synchronized (this.presences) {
- final String[] presencesArray = new String[presences.size()];
- presences.keySet().toArray(presencesArray);
- return presencesArray;
- }
- }
-
- public List<PresenceTemplate> asTemplates() {
- synchronized (this.presences) {
- ArrayList<PresenceTemplate> templates = new ArrayList<>(presences.size());
- for(Presence p : presences.values()) {
- if (p.getMessage() != null && !p.getMessage().trim().isEmpty()) {
- templates.add(new PresenceTemplate(p.getStatus(), p.getMessage()));
- }
- }
- return templates;
- }
- }
-
- public boolean has(String presence) {
- synchronized (this.presences) {
- return presences.containsKey(presence);
- }
- }
-
- public List<String> getStatusMessages() {
- ArrayList<String> messages = new ArrayList<>();
- synchronized (this.presences) {
- for(Presence presence : this.presences.values()) {
- String message = presence.getMessage() == null ? null : presence.getMessage().trim();
- if (message != null && !message.isEmpty() && !messages.contains(message)) {
- messages.add(message);
- }
- }
- }
- return messages;
- }
-
- public boolean allOrNonSupport(String namespace) {
- synchronized (this.presences) {
- for(Presence presence : this.presences.values()) {
- ServiceDiscoveryResult disco = presence.getServiceDiscoveryResult();
- if (disco == null || !disco.getFeatures().contains(namespace)) {
- return false;
- }
- }
- }
- return true;
- }
-
- public Pair<Map<String, String>,Map<String,String>> toTypeAndNameMap() {
- Map<String,String> typeMap = new HashMap<>();
- Map<String,String> nameMap = new HashMap<>();
- synchronized (this.presences) {
- for(Map.Entry<String,Presence> presenceEntry : this.presences.entrySet()) {
- String resource = presenceEntry.getKey();
- Presence presence = presenceEntry.getValue();
- ServiceDiscoveryResult serviceDiscoveryResult = presence == null ? null : presence.getServiceDiscoveryResult();
- if (serviceDiscoveryResult != null && serviceDiscoveryResult.getIdentities().size() > 0) {
- ServiceDiscoveryResult.Identity identity = serviceDiscoveryResult.getIdentities().get(0);
- String type = identity.getType();
- String name = identity.getName();
- if (type != null) {
- typeMap.put(resource,type);
- }
- if (name != null) {
- nameMap.put(resource, nameWithoutVersion(name));
- }
- }
- }
- }
- return new Pair<>(typeMap,nameMap);
- }
-
- private static String nameWithoutVersion(String name) {
- String[] parts = name.split(" ");
- if (parts.length > 1 && Character.isDigit(parts[parts.length -1].charAt(0))) {
- StringBuilder output = new StringBuilder();
- for(int i = 0; i < parts.length -1; ++i) {
- if (output.length() != 0) {
- output.append(' ');
- }
- output.append(parts[i]);
- }
- return output.toString();
- } else {
- return name;
- }
- }
+ private final Hashtable<String, Presence> presences = new Hashtable<>();
+
+ private static String nameWithoutVersion(String name) {
+ String[] parts = name.split(" ");
+ if (parts.length > 1 && Character.isDigit(parts[parts.length - 1].charAt(0))) {
+ StringBuilder output = new StringBuilder();
+ for (int i = 0; i < parts.length - 1; ++i) {
+ if (output.length() != 0) {
+ output.append(' ');
+ }
+ output.append(parts[i]);
+ }
+ return output.toString();
+ } else {
+ return name;
+ }
+ }
+
+ public List<Presence> getPresences() {
+ synchronized (this.presences) {
+ return new ArrayList<>(this.presences.values());
+ }
+ }
+
+ public Map<String, Presence> getPresencesMap() {
+ synchronized (this.presences) {
+ return new HashMap<>(this.presences);
+ }
+ }
+
+ public Presence get(String resource) {
+ synchronized (this.presences) {
+ return this.presences.get(resource);
+ }
+ }
+
+ public void updatePresence(String resource, Presence presence) {
+ synchronized (this.presences) {
+ this.presences.put(resource, presence);
+ }
+ }
+
+ public void removePresence(String resource) {
+ synchronized (this.presences) {
+ this.presences.remove(resource);
+ }
+ }
+
+ public void clearPresences() {
+ synchronized (this.presences) {
+ this.presences.clear();
+ }
+ }
+
+ public Presence.Status getShownStatus() {
+ Presence.Status status = Presence.Status.OFFLINE;
+ synchronized (this.presences) {
+ for (Presence p : presences.values()) {
+ if (p.getStatus() == Presence.Status.DND) {
+ return p.getStatus();
+ } else if (p.getStatus().compareTo(status) < 0) {
+ status = p.getStatus();
+ }
+ }
+ }
+ return status;
+ }
+
+ public int size() {
+ synchronized (this.presences) {
+ return presences.size();
+ }
+ }
+
+ public String[] toResourceArray() {
+ synchronized (this.presences) {
+ final String[] presencesArray = new String[presences.size()];
+ presences.keySet().toArray(presencesArray);
+ return presencesArray;
+ }
+ }
+
+ public List<PresenceTemplate> asTemplates() {
+ synchronized (this.presences) {
+ ArrayList<PresenceTemplate> templates = new ArrayList<>(presences.size());
+ for (Presence p : presences.values()) {
+ if (p.getMessage() != null && !p.getMessage().trim().isEmpty()) {
+ templates.add(new PresenceTemplate(p.getStatus(), p.getMessage()));
+ }
+ }
+ return templates;
+ }
+ }
+
+ public boolean has(String presence) {
+ synchronized (this.presences) {
+ return presences.containsKey(presence);
+ }
+ }
+
+ public List<String> getStatusMessages() {
+ ArrayList<String> messages = new ArrayList<>();
+ synchronized (this.presences) {
+ for (Presence presence : this.presences.values()) {
+ String message = presence.getMessage() == null ? null : presence.getMessage().trim();
+ if (message != null && !message.isEmpty() && !messages.contains(message)) {
+ messages.add(message);
+ }
+ }
+ }
+ return messages;
+ }
+
+ public boolean allOrNonSupport(String namespace) {
+ synchronized (this.presences) {
+ for (Presence presence : this.presences.values()) {
+ ServiceDiscoveryResult disco = presence.getServiceDiscoveryResult();
+ if (disco == null || !disco.getFeatures().contains(namespace)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public boolean anySupport(final String namespace) {
+ synchronized (this.presences) {
+ for (Presence presence : this.presences.values()) {
+ ServiceDiscoveryResult disco = presence.getServiceDiscoveryResult();
+ if (disco != null && disco.getFeatures().contains(namespace)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public Pair<Map<String, String>, Map<String, String>> toTypeAndNameMap() {
+ Map<String, String> typeMap = new HashMap<>();
+ Map<String, String> nameMap = new HashMap<>();
+ synchronized (this.presences) {
+ for (Map.Entry<String, Presence> presenceEntry : this.presences.entrySet()) {
+ String resource = presenceEntry.getKey();
+ Presence presence = presenceEntry.getValue();
+ ServiceDiscoveryResult serviceDiscoveryResult = presence == null ? null : presence.getServiceDiscoveryResult();
+ if (serviceDiscoveryResult != null && serviceDiscoveryResult.getIdentities().size() > 0) {
+ ServiceDiscoveryResult.Identity identity = serviceDiscoveryResult.getIdentities().get(0);
+ String type = identity.getType();
+ String name = identity.getName();
+ if (type != null) {
+ typeMap.put(resource, type);
+ }
+ if (name != null) {
+ nameMap.put(resource, nameWithoutVersion(name));
+ }
+ }
+ }
+ }
+ return new Pair<>(typeMap, nameMap);
+ }
}
@@ -116,6 +116,7 @@ import eu.siacs.conversations.utils.QuickLoader;
import eu.siacs.conversations.utils.StylingHelper;
import eu.siacs.conversations.utils.TimeFrameUtils;
import eu.siacs.conversations.utils.UIHelper;
+import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.chatstate.ChatState;
import eu.siacs.conversations.xmpp.jingle.AbstractJingleConnection;
@@ -1342,11 +1343,28 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
Toast.makeText(getActivity(), R.string.only_one_call_at_a_time, Toast.LENGTH_LONG).show();
return;
}
+
final Contact contact = conversation.getContact();
+ if (contact.getPresences().anySupport(Namespace.JINGLE_MESSAGE)) {
+ triggerRtpSession(contact.getAccount(),contact.getJid().asBareJid(),action);
+ } else {
+ final RtpCapability.Capability capability;
+ if (action.equals(RtpSessionActivity.ACTION_MAKE_VIDEO_CALL)) {
+ capability = RtpCapability.Capability.VIDEO;
+ } else {
+ capability = RtpCapability.Capability.AUDIO;
+ }
+ PresenceSelector.selectFullJidForDirectRtpConnection(activity, contact, capability, fullJid -> {
+ triggerRtpSession(contact.getAccount(), fullJid, action);
+ });
+ }
+ }
+
+ private void triggerRtpSession(final Account account, final Jid with, final String action) {
final Intent intent = new Intent(activity, RtpSessionActivity.class);
intent.setAction(action);
- intent.putExtra(RtpSessionActivity.EXTRA_ACCOUNT, contact.getAccount().getJid().toEscapedString());
- intent.putExtra(RtpSessionActivity.EXTRA_WITH, contact.getJid().asBareJid().toEscapedString());
+ intent.putExtra(RtpSessionActivity.EXTRA_ACCOUNT, account.getJid().toEscapedString());
+ intent.putExtra(RtpSessionActivity.EXTRA_WITH, with.toEscapedString());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
@@ -51,6 +51,7 @@ import eu.siacs.conversations.ui.util.AvatarWorkerTask;
import eu.siacs.conversations.ui.util.MainThreadExecutor;
import eu.siacs.conversations.utils.PermissionUtils;
import eu.siacs.conversations.utils.TimeFrameUtils;
+import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.jingle.AbstractJingleConnection;
import eu.siacs.conversations.xmpp.jingle.JingleRtpConnection;
import eu.siacs.conversations.xmpp.jingle.Media;
@@ -306,7 +307,13 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
private void proposeJingleRtpSession(final Account account, final Jid with, final Set<Media> media) {
checkMicrophoneAvailability();
- xmppConnectionService.getJingleConnectionManager().proposeJingleRtpSession(account, with, media);
+ if (with.isBareJid()) {
+ xmppConnectionService.getJingleConnectionManager().proposeJingleRtpSession(account, with, media);
+ } else {
+ final String sessionId = xmppConnectionService.getJingleConnectionManager().initializeRtpSession(account, with, media);
+ initializeActivityWithRunningRtpSession(account, with, sessionId);
+ resetIntent(account, with, sessionId);
+ }
putScreenInCallMode(media);
}
@@ -444,8 +451,12 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
return false;
}
- private void reInitializeActivityWithRunningRapSession(final Account account, Jid with, String sessionId) {
+ private void reInitializeActivityWithRunningRtpSession(final Account account, Jid with, String sessionId) {
runOnUiThread(() -> initializeActivityWithRunningRtpSession(account, with, sessionId));
+ resetIntent(account, with, sessionId);
+ }
+
+ private void resetIntent(final Account account, final Jid with, final String sessionId) {
final Intent intent = new Intent(Intent.ACTION_VIEW);
intent.putExtra(EXTRA_ACCOUNT, account.getJid().toEscapedString());
intent.putExtra(EXTRA_WITH, with.toEscapedString());
@@ -838,7 +849,6 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
}
private void retry(View view) {
- Log.d(Config.LOGTAG, "attempting retry");
final Intent intent = getIntent();
final Account account = extractAccount(intent);
final Jid with = Jid.ofEscaped(intent.getStringExtra(EXTRA_WITH));
@@ -846,6 +856,7 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
final String action = intent.getAction();
final Set<Media> media = actionToMedia(lastAction == null ? action : lastAction);
this.rtpConnectionReference = null;
+ Log.d(Config.LOGTAG, "attempting retry with " + with.toEscapedString());
proposeJingleRtpSession(account, with, media);
}
@@ -899,7 +910,7 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
return;
}
//this happens when going from proposed session to actual session
- reInitializeActivityWithRunningRapSession(account, with, sessionId);
+ reInitializeActivityWithRunningRtpSession(account, with, sessionId);
return;
}
final AbstractJingleConnection.Id id = requireRtpConnection().getId();
@@ -976,8 +987,12 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
private void resetIntent(final Account account, Jid with, final RtpEndUserState state, final Set<Media> media) {
final Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.putExtra(EXTRA_WITH, with.asBareJid().toEscapedString());
intent.putExtra(EXTRA_ACCOUNT, account.getJid().toEscapedString());
+ if (account.getRoster().getContact(with).getPresences().anySupport(Namespace.JINGLE_MESSAGE)) {
+ intent.putExtra(EXTRA_WITH, with.asBareJid().toEscapedString());
+ } else {
+ intent.putExtra(EXTRA_WITH, with.toEscapedString());
+ }
intent.putExtra(EXTRA_LAST_REPORTED_STATE, state.toString());
intent.putExtra(EXTRA_LAST_ACTION, media.contains(Media.VIDEO) ? ACTION_MAKE_VIDEO_CALL : ACTION_MAKE_VOICE_CALL);
setIntent(intent);
@@ -44,92 +44,110 @@ import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Presences;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.xmpp.Jid;
+import eu.siacs.conversations.xmpp.jingle.RtpCapability;
public class PresenceSelector {
- public static void showPresenceSelectionDialog(Activity activity, final Conversation conversation, final OnPresenceSelected listener) {
- final Contact contact = conversation.getContact();
- final Presences presences = contact.getPresences();
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
- builder.setTitle(activity.getString(R.string.choose_presence));
- final String[] resourceArray = presences.toResourceArray();
- Pair<Map<String, String>, Map<String, String>> typeAndName = presences.toTypeAndNameMap();
- final Map<String, String> resourceTypeMap = typeAndName.first;
- final Map<String, String> resourceNameMap = typeAndName.second;
- final String[] readableIdentities = new String[resourceArray.length];
- final AtomicInteger selectedResource = new AtomicInteger(0);
- for (int i = 0; i < resourceArray.length; ++i) {
- String resource = resourceArray[i];
- if (resource.equals(contact.getLastResource())) {
- selectedResource.set(i);
- }
- String type = resourceTypeMap.get(resource);
- String name = resourceNameMap.get(resource);
- if (type != null) {
- if (Collections.frequency(resourceTypeMap.values(), type) == 1) {
- readableIdentities[i] = translateType(activity, type);
- } else if (name != null) {
- if (Collections.frequency(resourceNameMap.values(), name) == 1
- || CryptoHelper.UUID_PATTERN.matcher(resource).matches()) {
- readableIdentities[i] = translateType(activity, type) + " (" + name + ")";
- } else {
- readableIdentities[i] = translateType(activity, type) + " (" + name + " / " + resource + ")";
- }
- } else {
- readableIdentities[i] = translateType(activity, type) + " (" + resource + ")";
- }
- } else {
- readableIdentities[i] = resource;
- }
- }
- builder.setSingleChoiceItems(readableIdentities,
- selectedResource.get(),
- (dialog, which) -> selectedResource.set(which));
- builder.setNegativeButton(R.string.cancel, null);
- builder.setPositiveButton(R.string.ok, (dialog, which) -> {
- try {
- Jid next = Jid.of(contact.getJid().getLocal(), contact.getJid().getDomain(), resourceArray[selectedResource.get()]);
- conversation.setNextCounterpart(next);
- } catch (IllegalArgumentException e) {
- conversation.setNextCounterpart(null);
- }
- listener.onPresenceSelected();
- });
- builder.create().show();
- }
+ public static void showPresenceSelectionDialog(Activity activity, final Conversation conversation, final OnPresenceSelected listener) {
+ final Contact contact = conversation.getContact();
+ final String[] resourceArray = contact.getPresences().toResourceArray();
+ showPresenceSelectionDialog(activity, contact, resourceArray, fullJid -> {
+ conversation.setNextCounterpart(fullJid);
+ listener.onPresenceSelected();
+ });
+ }
- public static void warnMutualPresenceSubscription(Activity activity, final Conversation conversation, final OnPresenceSelected listener) {
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
- builder.setTitle(conversation.getContact().getJid().toString());
- builder.setMessage(R.string.without_mutual_presence_updates);
- builder.setNegativeButton(R.string.cancel, null);
- builder.setPositiveButton(R.string.ignore, (dialog, which) -> {
- conversation.setNextCounterpart(null);
- if (listener != null) {
- listener.onPresenceSelected();
- }
- });
- builder.create().show();
- }
+ public static void selectFullJidForDirectRtpConnection(final Activity activity, final Contact contact, final RtpCapability.Capability required, final OnFullJidSelected onFullJidSelected) {
+ final String[] resources = RtpCapability.filterPresences(contact, required);
+ if (resources.length == 1) {
+ onFullJidSelected.onFullJidSelected(contact.getJid().withResource(resources[0]));
+ } else {
+ showPresenceSelectionDialog(activity, contact, resources, onFullJidSelected);
+ }
+ }
- private static String translateType(Context context, String type) {
- switch (type.toLowerCase()) {
- case "pc":
- return context.getString(R.string.type_pc);
- case "phone":
- return context.getString(R.string.type_phone);
- case "tablet":
- return context.getString(R.string.type_tablet);
- case "web":
- return context.getString(R.string.type_web);
- case "console":
- return context.getString(R.string.type_console);
- default:
- return type;
- }
- }
+ private static void showPresenceSelectionDialog(final Activity activity, final Contact contact, final String[] resourceArray, final OnFullJidSelected onFullJidSelected) {
+ final Presences presences = contact.getPresences();
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ builder.setTitle(activity.getString(R.string.choose_presence));
+ Pair<Map<String, String>, Map<String, String>> typeAndName = presences.toTypeAndNameMap();
+ final Map<String, String> resourceTypeMap = typeAndName.first;
+ final Map<String, String> resourceNameMap = typeAndName.second;
+ final String[] readableIdentities = new String[resourceArray.length];
+ final AtomicInteger selectedResource = new AtomicInteger(0);
+ for (int i = 0; i < resourceArray.length; ++i) {
+ String resource = resourceArray[i];
+ if (resource.equals(contact.getLastResource())) {
+ selectedResource.set(i);
+ }
+ String type = resourceTypeMap.get(resource);
+ String name = resourceNameMap.get(resource);
+ if (type != null) {
+ if (Collections.frequency(resourceTypeMap.values(), type) == 1) {
+ readableIdentities[i] = translateType(activity, type);
+ } else if (name != null) {
+ if (Collections.frequency(resourceNameMap.values(), name) == 1
+ || CryptoHelper.UUID_PATTERN.matcher(resource).matches()) {
+ readableIdentities[i] = translateType(activity, type) + " (" + name + ")";
+ } else {
+ readableIdentities[i] = translateType(activity, type) + " (" + name + " / " + resource + ")";
+ }
+ } else {
+ readableIdentities[i] = translateType(activity, type) + " (" + resource + ")";
+ }
+ } else {
+ readableIdentities[i] = resource;
+ }
+ }
+ builder.setSingleChoiceItems(readableIdentities,
+ selectedResource.get(),
+ (dialog, which) -> selectedResource.set(which));
+ builder.setNegativeButton(R.string.cancel, null);
+ builder.setPositiveButton(
+ R.string.ok,
+ (dialog, which) -> onFullJidSelected.onFullJidSelected(
+ Jid.of(contact.getJid().getLocal(), contact.getJid().getDomain(), resourceArray[selectedResource.get()])
+ )
+ );
+ builder.create().show();
+ }
- public interface OnPresenceSelected {
- void onPresenceSelected();
- }
+ public static void warnMutualPresenceSubscription(Activity activity, final Conversation conversation, final OnPresenceSelected listener) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ builder.setTitle(conversation.getContact().getJid().toString());
+ builder.setMessage(R.string.without_mutual_presence_updates);
+ builder.setNegativeButton(R.string.cancel, null);
+ builder.setPositiveButton(R.string.ignore, (dialog, which) -> {
+ conversation.setNextCounterpart(null);
+ if (listener != null) {
+ listener.onPresenceSelected();
+ }
+ });
+ builder.create().show();
+ }
+
+ private static String translateType(Context context, String type) {
+ switch (type.toLowerCase()) {
+ case "pc":
+ return context.getString(R.string.type_pc);
+ case "phone":
+ return context.getString(R.string.type_phone);
+ case "tablet":
+ return context.getString(R.string.type_tablet);
+ case "web":
+ return context.getString(R.string.type_web);
+ case "console":
+ return context.getString(R.string.type_console);
+ default:
+ return type;
+ }
+ }
+
+ public interface OnPresenceSelected {
+ void onPresenceSelected();
+ }
+
+ public interface OnFullJidSelected {
+ void onFullJidSelected(Jid jid);
+ }
}
@@ -62,6 +62,10 @@ public abstract class AbstractJingleConnection {
return new Id(account, with, sessionId);
}
+ public static Id of(Account account, Jid with) {
+ return new Id(account, with, JingleConnectionManager.nextRandomId());
+ }
+
public static Id of(Message message) {
return new Id(
message.getConversation().getAccount(),
@@ -11,6 +11,7 @@ import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Collections2;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.ImmutableSet;
+import com.google.j2objc.annotations.Weak;
import java.lang.ref.WeakReference;
import java.security.SecureRandom;
@@ -523,6 +524,15 @@ public class JingleConnectionManager extends AbstractConnectionManager {
mXmppConnectionService.sendMessagePacket(account, messagePacket);
}
+ public String initializeRtpSession(final Account account, final Jid with, final Set<Media> media) {
+ final AbstractJingleConnection.Id id = AbstractJingleConnection.Id.of(account, with);
+ final JingleRtpConnection rtpConnection = new JingleRtpConnection(this, id, account.getJid());
+ rtpConnection.setProposedMedia(media);
+ this.connections.put(id, rtpConnection);
+ rtpConnection.sendSessionInitiate();
+ return id.sessionId;
+ }
+
public void proposeJingleRtpSession(final Account account, final Jid with, final Set<Media> media) {
synchronized (this.rtpSessionProposals) {
for (Map.Entry<RtpSessionProposal, DeviceDiscoveryState> entry : this.rtpSessionProposals.entrySet()) {
@@ -640,6 +640,10 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
}
}
+ public void sendSessionInitiate() {
+ sendSessionInitiate(this.proposedMedia, State.SESSION_INITIALIZED);
+ }
+
private void sendSessionInitiate(final Set<Media> media, final State targetState) {
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": prepare session-initiate");
discoverIceServers(iceServers -> sendSessionInitiate(media, targetState, iceServers));
@@ -781,6 +785,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
public RtpEndUserState getEndUserState() {
switch (this.state) {
+ case NULL:
case PROPOSED:
case SESSION_INITIALIZED:
if (isInitiator()) {
@@ -836,10 +841,19 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
public Set<Media> getMedia() {
final State current = getState();
if (current == State.NULL) {
+ if (isInitiator()) {
+ return Preconditions.checkNotNull(
+ this.proposedMedia,
+ "RTP connection has not been initialized properly"
+ );
+ }
throw new IllegalStateException("RTP connection has not been initialized yet");
}
if (Arrays.asList(State.PROPOSED, State.PROCEED).contains(current)) {
- return Preconditions.checkNotNull(this.proposedMedia, "RTP connection has not been initialized properly");
+ return Preconditions.checkNotNull(
+ this.proposedMedia,
+ "RTP connection has not been initialized properly"
+ );
}
final RtpContentMap initiatorContentMap = initiatorRtpContentMap;
if (initiatorContentMap != null) {
@@ -1,8 +1,10 @@
package eu.siacs.conversations.xmpp.jingle;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Presence;
@@ -37,6 +39,21 @@ public class RtpCapability {
return Capability.NONE;
}
+ public static String[] filterPresences(final Contact contact, Capability required) {
+ final Presences presences = contact.getPresences();
+ final ArrayList<String> resources = new ArrayList<>();
+ for(final Map.Entry<String,Presence> presence : presences.getPresencesMap().entrySet()) {
+ final Capability capability = check(presence.getValue());
+ if (capability == Capability.NONE) {
+ continue;
+ }
+ if (required == Capability.AUDIO || capability == required) {
+ resources.add(presence.getKey());
+ }
+ }
+ return resources.toArray(new String[0]);
+ }
+
public static Capability check(final Contact contact) {
final Presences presences = contact.getPresences();
Capability result = Capability.NONE;