/* * TeleStax, Open Source Cloud Communications * Copyright 2011-2014, Telestax Inc and individual contributors * by the @authors tag. * * This program is free software: you can redistribute it and/or modify * under the terms of the GNU Affero General Public License as * published by the Free Software Foundation; either version 3 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/> * */ package org.restcomm.media.ice.harvest; import java.net.InetAddress; import java.nio.channels.Selector; import java.util.HashMap; import java.util.Map; import org.restcomm.media.ice.CandidateType; import org.restcomm.media.ice.FoundationsRegistry; import org.restcomm.media.ice.IceMediaStream; import org.restcomm.media.ice.lite.LiteFoundationsRegistry; import org.restcomm.media.network.deprecated.RtpPortManager; /** * Manages the candidate harvesting process * * @author Henrique Rosa * */ public class HarvestManager { private final FoundationsRegistry foundations; private final Map<CandidateType, CandidateHarvester> harvesters; private InetAddress externalAddress; public HarvestManager() { this.foundations = new LiteFoundationsRegistry(); this.harvesters = new HashMap<CandidateType, CandidateHarvester>( CandidateType.count()); this.harvesters.put(CandidateType.HOST, new HostCandidateHarvester( this.foundations)); } /** * Registers a harvester for a certain type of candidates. <b> Only * <b>one</b> harvester per candidate type is supported. * * @param harvester * The harvester to be registered * @return Whether the harvester was successfully registered or not. */ public boolean addHarvester(CandidateHarvester harvester) { CandidateType candidateType = harvester.getCandidateType(); boolean added = false; synchronized (this.harvesters) { if (!this.harvesters.containsKey(candidateType)) { this.harvesters.put(candidateType, harvester); added = true; } else { added = false; } } return added; } public CandidateHarvester removeHarvester(CandidateType type) { synchronized (this.harvesters) { return this.harvesters.remove(type); } } /** * Gets the foundations registry managed during the lifetime of the ICE * agent. * * @return The foundations registry */ public FoundationsRegistry getFoundationsRegistry() { return this.foundations; } public InetAddress getExternalAddress() { return externalAddress; } public void harvest(IceMediaStream mediaStream, RtpPortManager portManager, Selector selector) throws HarvestException, NoCandidatesGatheredException { // Ask each harvester to gather candidates for the media stream // HOST candidates take precedence and are mandatory CandidateHarvester hostHarvester = harvesters.get(CandidateType.HOST); if (hostHarvester != null) { hostHarvester.harvest(portManager, mediaStream, selector); } else { throw new HarvestException("No HOST harvester registered!"); } // Then comes the SRFLX, which depends on HOST candidates CandidateHarvester srflxHarvester = harvesters.get(CandidateType.SRFLX); if (srflxHarvester != null) { srflxHarvester.harvest(portManager, mediaStream, selector); } // RELAY candidates come last CandidateHarvester relayHarvester = harvesters.get(CandidateType.RELAY); if (relayHarvester != null) { relayHarvester.harvest(portManager, mediaStream, selector); } // Verify at least one candidate was gathered if (!mediaStream.hasLocalRtpCandidates()) { throw new NoCandidatesGatheredException("No RTP candidates were gathered for " + mediaStream.getName() + " stream"); } // After harvesting all possible candidates, ask the media stream to // select its default local candidates mediaStream.getRtpComponent().selectDefaultLocalCandidate(); if (mediaStream.supportsRtcp() && !mediaStream.isRtcpMux()) { mediaStream.getRtcpComponent().selectDefaultLocalCandidate(); } } }