/*
* Jicofo, the Jitsi Conference Focus.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jitsi.jicofo;
import net.java.sip.communicator.impl.protocol.jabber.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.colibri.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.jirecon.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
import org.jitsi.protocol.xmpp.*;
import java.util.*;
/**
* Class handles discovery of Jitsi Meet application services like bridge,
* recording, SIP gateway and so on...
*
* @author Pawel Domas
*/
public class JitsiMeetServices
implements RegistrationStateChangeListener
{
/**
* The logger
*/
private final static Logger logger
= Logger.getLogger(JitsiMeetServices.class);
/**
* Feature set advertised by videobridge.
*/
public static final String[] VIDEOBRIDGE_FEATURES = new String[]
{
ColibriConferenceIQ.NAMESPACE,
ProtocolProviderServiceJabberImpl
.URN_XMPP_JINGLE_DTLS_SRTP,
ProtocolProviderServiceJabberImpl
.URN_XMPP_JINGLE_ICE_UDP_1,
ProtocolProviderServiceJabberImpl
.URN_XMPP_JINGLE_RAW_UDP_0
};
/**
* Features advertised by Jirecon recorder container.
*/
private static final String[] JIRECON_RECORDER_FEATURES = new String[]
{
JireconIqProvider.NAMESPACE
};
/**
* Features advertised by SIP gateway component.
*/
private static final String[] SIP_GW_FEATURES = new String[]
{
"http://jitsi.org/protocol/jigasi",
"urn:xmpp:rayo:0"
};
/**
* Features used to recognize pub-sub service.
*/
private static final String[] PUBSUB_FEATURES = new String[]
{
"http://jabber.org/protocol/pubsub",
"http://jabber.org/protocol/pubsub#subscribe"
};
/**
* Capabilities operation set used to discover services info.
*/
private OperationSetSimpleCaps capsOpSet;
/**
* XMPP xmppDomain for which we're discovering service info.
*/
private String xmppDomain;
/**
* Videobridge component XMPP address.
*/
private BridgeSelector bridgeSelector;
/**
* The protocol service handler that provides XMPP service.
*/
private ProtocolProviderHandler protocolProviderHandler;
/**
* Jirecon recorder component XMPP address.
*/
private String jireconRecorder;
/**
* SIP gateway component XMPP address.
*/
private String sipGateway;
/**
* Starts this instance.
*
* @param xmppDomain server address/main service XMPP xmppDomain that hosts
* the conference system.
* @param xmppAuthDomain the xmppDomain used for XMPP authentication.
* @param xmppUserName the user name used to login.
* @param xmppLoginPassword the password used for authentication.
*
* @throws java.lang.IllegalStateException if started already.
*/
public void start(String serverAddress,
String xmppDomain,
String xmppAuthDomain,
String xmppUserName,
String xmppLoginPassword)
{
if (protocolProviderHandler != null)
{
throw new IllegalStateException("Already started");
}
this.xmppDomain = xmppDomain;
this.protocolProviderHandler
= new ProtocolProviderHandler();
protocolProviderHandler.start(
serverAddress, xmppAuthDomain, xmppLoginPassword,
xmppUserName, this);
this.capsOpSet
= protocolProviderHandler.getOperationSet(
OperationSetSimpleCaps.class);
this.bridgeSelector
= new BridgeSelector(
protocolProviderHandler
.getProtocolProvider()
.getOperationSet(OperationSetSubscription.class));
if (protocolProviderHandler.isRegistered())
{
init();
}
else
{
protocolProviderHandler.register();
}
}
/**
* Stops this instance and disposes XMPP connection.
*/
public void stop()
{
if (protocolProviderHandler != null)
{
protocolProviderHandler.stop();
protocolProviderHandler = null;
}
}
/**
* Initializes this instance and discovers Jitsi Meet services.
*/
public void init()
{
List<String> items = capsOpSet.getItems(xmppDomain);
for (String item : items)
{
if (capsOpSet.hasFeatureSupport(item, VIDEOBRIDGE_FEATURES))
{
logger.info("Discovered videobridge: " + item);
bridgeSelector.addJvbAddress(item);
}
else if (jireconRecorder == null
&& capsOpSet.hasFeatureSupport(item, JIRECON_RECORDER_FEATURES))
{
logger.info("Discovered Jirecon recorder: " + item);
setJireconRecorder(item);
}
else if (sipGateway == null
&& capsOpSet.hasFeatureSupport(item, SIP_GW_FEATURES))
{
logger.info("Discovered SIP gateway: " + item);
setSipGateway(item);
}
/*
FIXME: pub-sub service auto-detect ?
else if (capsOpSet.hasFeatureSupport(item, PUBSUB_FEATURES))
{
// Potential PUBSUB service
logger.info("Potential PUBSUB service:" + item);
List<String> subItems = capsOpSet.getItems(item);
for (String subItem: subItems)
{
logger.info("Subnode " + subItem + " of " + item);
capsOpSet.hasFeatureSupport(
item, subItem, VIDEOBRIDGE_FEATURES);
}
}*/
}
}
/**
* Returns the XMPP address of videobridge component.
*/
public String getVideobridge()
{
return bridgeSelector.selectVideobridge();
}
/**
* Sets new XMPP address of the SIP gateway component.
* @param sipGateway the XMPP address to be set as SIP gateway component
* address.
*/
private void setSipGateway(String sipGateway)
{
this.sipGateway = sipGateway;
}
/**
* Sets new XMPP address of the Jirecon jireconRecorder component.
* @param jireconRecorder the XMPP address to be set as Jirecon recorder
* component address.
*/
public void setJireconRecorder(String jireconRecorder)
{
this.jireconRecorder = jireconRecorder;
}
/**
* Returns the XMPP address of Jirecon recorder component.
*/
public String getJireconRecorder()
{
return jireconRecorder;
}
/**
* Returns {@link BridgeSelector} bound to this instance that can be used to
* select the videobridge on the xmppDomain handled by this instance.
*/
public BridgeSelector getBridgeSelector()
{
return bridgeSelector;
}
@Override
public void registrationStateChanged(RegistrationStateChangeEvent evt)
{
//FIXME: do something here (start PBU-SUB)
if (RegistrationState.REGISTERED.equals(evt.getNewState()))
{
init();
}
}
/**
* Returns capabilities operation set used by this instance to discover
* services info.
*/
public OperationSetSimpleCaps getCapsOpSet()
{
return capsOpSet;
}
}