/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.java.sip.communicator.impl.protocol.jabber.extensions.colibri;
import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*;
import net.java.sip.communicator.impl.protocol.jabber.jinglesdp.*;
import net.java.sip.communicator.util.*;
import org.jitsi.service.neomedia.*;
import java.util.*;
/**
* Utility class for extracting info from responses received from the JVB and
* keeping track of conference state.
*
* @author Pawel Domas
*/
public class ColibriAnalyser
{
/**
* The logger used by this instance.
*/
private final static Logger logger
= Logger.getLogger(ColibriAnalyser.class);
/**
* Colibri IQ instance used to store conference state.
*/
private final ColibriConferenceIQ conferenceState;
/**
* Creates new instance of analyser that will used given Colibri IQ instance
* for storing conference state.
* @param conferenceStateHolder the Colibri IQ instance that will be used
* for storing conference state.
*/
public ColibriAnalyser(ColibriConferenceIQ conferenceStateHolder)
{
this.conferenceState = conferenceStateHolder;
}
/**
* Processes channels allocation response from the JVB and stores info about
* new channels in {@link #conferenceState}.
* @param allocateResponse the Colibri IQ that describes JVB response to
* allocate request.
*/
public void processChannelAllocResp(ColibriConferenceIQ allocateResponse)
{
String conferenceResponseID = allocateResponse.getID();
String colibriID = conferenceState.getID();
if (colibriID == null)
conferenceState.setID(conferenceResponseID);
else if (!colibriID.equals(conferenceResponseID))
throw new IllegalStateException("conference.id");
/*
* XXX We must remember the JID of the Jitsi Videobridge because
* (1) we do not want to re-discover it in every method
* invocation on this Call instance and (2) we want to use one
* and the same for all CallPeers within this Call instance.
*/
conferenceState.setFrom(allocateResponse.getFrom());
for (ColibriConferenceIQ.Content contentResponse
: allocateResponse.getContents())
{
String contentName = contentResponse.getName();
ColibriConferenceIQ.Content content
= conferenceState.getOrCreateContent(contentName);
// FIXME: we do not check if allocated channel does not clash
// with any existing one
for (ColibriConferenceIQ.Channel channelResponse
: contentResponse.getChannels())
{
content.addChannel(channelResponse);
}
for (ColibriConferenceIQ.SctpConnection sctpConnResponse
: contentResponse.getSctpConnections())
{
content.addSctpConnection(sctpConnResponse);
}
}
for (ColibriConferenceIQ.ChannelBundle bundle
: allocateResponse.getChannelBundles())
{
conferenceState.addChannelBundle(bundle);
}
}
/**
* Utility method for extracting info about channels allocated from JVB
* response.
* FIXME: this might not work as expected when channels for multiple peers
* with single query were allocated.
* @param conferenceResponse JVB response to allocate channels request.
* @param peerContents list of peer media contents that has to be matched
* with allocated channels.
* @return the Colibri IQ that describes allocated channels.
*/
public static ColibriConferenceIQ getResponseContents(
ColibriConferenceIQ conferenceResponse,
List<ContentPacketExtension> peerContents)
{
ColibriConferenceIQ conferenceResult = new ColibriConferenceIQ();
conferenceResult.setFrom(conferenceResponse.getFrom());
conferenceResult.setID(conferenceResponse.getID());
conferenceResult.setGID(conferenceResponse.getGID());
conferenceResult.setName(conferenceResponse.getName());
// FIXME: we support single bundle for all channels
String bundleId = null;
for (ContentPacketExtension content : peerContents)
{
MediaType mediaType
= JingleUtils.getMediaType(content);
ColibriConferenceIQ.Content contentResponse
= conferenceResponse.getContent(mediaType.toString());
if (contentResponse != null)
{
String contentName = contentResponse.getName();
ColibriConferenceIQ.Content contentResult
= new ColibriConferenceIQ.Content(contentName);
conferenceResult.addContent(contentResult);
for (ColibriConferenceIQ.Channel channelResponse
: contentResponse.getChannels())
{
contentResult.addChannel(channelResponse);
bundleId = readChannelBundle(channelResponse, bundleId);
}
for (ColibriConferenceIQ.SctpConnection sctpConnResponse
: contentResponse.getSctpConnections())
{
contentResult.addSctpConnection(sctpConnResponse);
bundleId = readChannelBundle(sctpConnResponse, bundleId);
}
}
}
// Copy only peer's bundle(JVB returns all bundles)
if (bundleId != null)
{
for (ColibriConferenceIQ.ChannelBundle bundle
: conferenceResponse.getChannelBundles())
{
if (bundleId.equals(bundle.getId()))
{
conferenceResult.addChannelBundle(bundle);
break;
}
}
}
return conferenceResult;
}
/**
* Utility method for getting actual channel bundle. If
* <tt>currentBundle</tt> is <tt>null</tt> then <tt>channels</tt> bundle is
* returned(and vice-versa). If both channel's and given bundle IDs are not
* null then they are compared and error is logged, but channel's bundle is
* returned in the last place anyway.
*/
private static String readChannelBundle(
ColibriConferenceIQ.ChannelCommon channel, String currentBundle)
{
String channelBundle = channel.getChannelBundleId();
if (channelBundle == null)
{
return currentBundle;
}
if (currentBundle == null)
{
return channel.getChannelBundleId();
}
else
{
// Compare to detect problems
if (!currentBundle.equals(channelBundle))
{
logger.error(
"Replaced bundle: " + currentBundle
+ " with " + channelBundle);
}
return channelBundle;
}
}
}