Java tutorial
/* * (C) Copyright 2014 Kurento (http://kurento.org/) * * 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 org.kurento.demo; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ConcurrentHashMap; import javax.annotation.PostConstruct; import org.kurento.client.EndOfStreamEvent; import org.kurento.client.ErrorEvent; import org.kurento.client.EventListener; import org.kurento.client.IceCandidate; import org.kurento.client.KurentoClient; import org.kurento.client.MediaPipeline; import org.kurento.client.PlayerEndpoint; import org.kurento.client.WebRtcEndpoint; import org.kurento.module.crowddetector.CrowdDetectorDirectionEvent; import org.kurento.module.crowddetector.CrowdDetectorFilter; import org.kurento.module.crowddetector.CrowdDetectorFluidityEvent; import org.kurento.module.crowddetector.CrowdDetectorOccupancyEvent; import org.kurento.module.crowddetector.RegionOfInterest; import org.kurento.module.crowddetector.RegionOfInterestConfig; import org.kurento.module.crowddetector.RelativePoint; import org.kurento.orion.OrionConnectorException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; public class Pipeline { private static final Logger log = LoggerFactory.getLogger(Pipeline.class); private static final long RECONNECTION_TIME = 30 * 1000; @Autowired private ConfigurationReader configuration; @Autowired private KurentoClient kurento; @Autowired private CrowdDetectorOrionPublisher orionPublisher; private MediaPipeline pipe; private PlayerEndpoint playerEndpoint; private CrowdDetectorFilter crowdDetectorFilter; private String feedUrl; private List<RegionOfInterest> rois; private final Map<String, WebRtcEndpoint> webRtcEndpoints = new ConcurrentHashMap<>(); private boolean playing; private Timer timer; @PostConstruct public void init() { this.pipe = this.kurento.createMediaPipeline(); this.rois = new ArrayList<>(); JsonArray loadedRois; JsonObject config = this.configuration.getConfig(); if (config != null) { JsonElement feedUrlJson = config.get("feedUrl"); if (feedUrlJson != null) { this.feedUrl = feedUrlJson.getAsString(); } else { log.debug("Url feed not defined."); } JsonElement loadedRoisJson = config.get("rois"); if (loadedRoisJson != null) { loadedRois = loadedRoisJson.getAsJsonArray(); this.rois = readRoisFromJson(loadedRois); } else { this.rois = getDummyRois(); log.debug("Rois not defined. Using dummy rois"); } } if (this.feedUrl == null) { // PlayerEndpoint will be configured later. return; } try { this.orionPublisher.registerRoisInOrion(this.rois); } catch (OrionConnectorException e) { log.warn("Could not register ROIs in ORION"); } this.crowdDetectorFilter = new CrowdDetectorFilter.Builder(this.pipe, this.rois).build(); this.crowdDetectorFilter.setProcessingWidth(640); addOrionListeners(); this.playerEndpoint = new PlayerEndpoint.Builder(this.pipe, this.feedUrl).build(); addPlayerListeners(); this.playing = true; this.playerEndpoint.connect(this.crowdDetectorFilter); this.playerEndpoint.play(); } private void addPlayerListeners() { this.playerEndpoint.addEndOfStreamListener(new EventListener<EndOfStreamEvent>() { @Override public void onEvent(EndOfStreamEvent event) { log.warn("Received EOS from Player"); if (Pipeline.this.timer != null) { try { Pipeline.this.timer.cancel(); } catch (Exception e) { log.debug("Empty timer"); } } setFeedUrl(Pipeline.this.feedUrl); } }); this.playerEndpoint.addErrorListener(new EventListener<ErrorEvent>() { @Override public void onEvent(ErrorEvent event) { synchronized (this) { log.error("Error received from Media server" + event.getDescription() + " " + event.getErrorCode() + " " + event.getType()); if (Pipeline.this.playing) { Pipeline.this.playing = false; log.error("Timer added to create the player again"); Pipeline.this.timer = new Timer(); TimerTask task = new TimerTask() { @Override public void run() { setFeedUrl(Pipeline.this.feedUrl); } }; Pipeline.this.timer.schedule(task, RECONNECTION_TIME); } } } }); } private static List<RegionOfInterest> readRoisFromJson(JsonArray loadedRois) { List<RegionOfInterest> rois = new ArrayList<>(); for (int j = 0; j < loadedRois.size(); j++) { JsonObject roi = (JsonObject) loadedRois.get(j); JsonArray coordinates = (JsonArray) roi.get("points"); // create structure to configure crowddetector List<RelativePoint> points = new ArrayList<>(coordinates.size()); for (int i = 0; i < coordinates.size(); i++) { JsonObject coordinate = coordinates.get(i).getAsJsonObject(); float x = coordinate.getAsJsonPrimitive("x").getAsFloat(); float y = coordinate.getAsJsonPrimitive("y").getAsFloat(); if (x > 1) { x = 1; } if (y > 1) { y = 1; } points.add(new RelativePoint(x, y)); } RegionOfInterestConfig config = new RegionOfInterestConfig(); config.setFluidityLevelMin(roi.getAsJsonPrimitive("fluidityLevelMin").getAsInt()); config.setFluidityLevelMed(roi.getAsJsonPrimitive("fluidityLevelMed").getAsInt()); config.setFluidityLevelMax(roi.getAsJsonPrimitive("fluidityLevelMax").getAsInt()); config.setFluidityNumFramesToEvent(roi.getAsJsonPrimitive("fluidityNumFramesToEvent").getAsInt()); config.setOccupancyLevelMin(roi.getAsJsonPrimitive("occupancyLevelMin").getAsInt()); config.setOccupancyLevelMed(roi.getAsJsonPrimitive("occupancyLevelMed").getAsInt()); config.setOccupancyLevelMax(roi.getAsJsonPrimitive("occupancyLevelMax").getAsInt()); config.setOccupancyNumFramesToEvent(roi.getAsJsonPrimitive("occupancyNumFramesToEvent").getAsInt()); config.setSendOpticalFlowEvent(roi.getAsJsonPrimitive("sendOpticalFlowEvent").getAsBoolean()); config.setOpticalFlowNumFramesToEvent(roi.getAsJsonPrimitive("opticalFlowNumFramesToEvent").getAsInt()); config.setOpticalFlowNumFramesToReset(roi.getAsJsonPrimitive("opticalFlowNumFramesToReset").getAsInt()); config.setOpticalFlowAngleOffset(roi.getAsJsonPrimitive("opticalFlowAngleOffset").getAsInt()); rois.add(new RegionOfInterest(points, config, roi.getAsJsonPrimitive("id").getAsString())); } return rois; } private static List<RegionOfInterest> getDummyRois() { List<RelativePoint> points = new ArrayList<>(); float x = 0; float y = 0; points.add(new RelativePoint(x, y)); x = 1; y = 0; points.add(new RelativePoint(x, y)); x = 1; y = 1; points.add(new RelativePoint(x, y)); x = 0; y = 1; points.add(new RelativePoint(x, y)); RegionOfInterestConfig config = new RegionOfInterestConfig(); config.setFluidityLevelMin(10); config.setFluidityLevelMed(35); config.setFluidityLevelMax(65); config.setFluidityNumFramesToEvent(5); config.setOccupancyLevelMin(10); config.setOccupancyLevelMed(35); config.setOccupancyLevelMax(65); config.setOccupancyNumFramesToEvent(5); config.setSendOpticalFlowEvent(false); config.setOpticalFlowNumFramesToEvent(3); config.setOpticalFlowNumFramesToReset(3); config.setOpticalFlowAngleOffset(0); List<RegionOfInterest> rois = new ArrayList<>(); rois.add(new RegionOfInterest(points, config, "dummyRoy")); return rois; } public void addOrionListeners() { this.crowdDetectorFilter .addCrowdDetectorDirectionListener(new EventListener<CrowdDetectorDirectionEvent>() { @Override public void onEvent(CrowdDetectorDirectionEvent event) { try { Pipeline.this.orionPublisher.publishEvent(event); } catch (OrionConnectorException e) { log.warn("Could not publish event in ORION"); } log.debug("Direction event detected in roi {} direction {}", event.getRoiID(), event.getDirectionAngle()); } }); this.crowdDetectorFilter.addCrowdDetectorFluidityListener(new EventListener<CrowdDetectorFluidityEvent>() { @Override public void onEvent(CrowdDetectorFluidityEvent event) { try { Pipeline.this.orionPublisher.publishEvent(event); } catch (OrionConnectorException e) { log.warn("Could not publish event in ORION"); } log.debug("Fluidity event detected in roi {} percentage {} level {}", event.getRoiID(), event.getFluidityPercentage(), event.getFluidityLevel()); } }); this.crowdDetectorFilter .addCrowdDetectorOccupancyListener(new EventListener<CrowdDetectorOccupancyEvent>() { @Override public void onEvent(CrowdDetectorOccupancyEvent event) { try { Pipeline.this.orionPublisher.publishEvent(event); } catch (OrionConnectorException e) { log.warn("Could not publish event in ORION"); } log.debug("Occupancy event detected in roi {} percentage {} level {}", event.getRoiID(), event.getOccupancyPercentage(), event.getOccupancyLevel()); } }); } public CrowdDetectorFilter getCrowdDetectorFilter() { return this.crowdDetectorFilter; } public PlayerEndpoint getPlayerEndpoint() { return this.playerEndpoint; } public String getFeedUrl() { return this.feedUrl; } public void setFeedUrl(String feedUrl) { this.feedUrl = feedUrl; if (this.playerEndpoint != null) { log.debug("Releasing previous elements"); this.crowdDetectorFilter.release(); this.playerEndpoint.release(); } log.debug("Creating new elements"); this.crowdDetectorFilter = new CrowdDetectorFilter.Builder(this.pipe, this.rois).build(); this.crowdDetectorFilter.setProcessingWidth(640); addOrionListeners(); this.playerEndpoint = new PlayerEndpoint.Builder(this.pipe, this.feedUrl).build(); addPlayerListeners(); this.playing = true; this.playerEndpoint.connect(this.crowdDetectorFilter); this.playerEndpoint.play(); log.debug("New player is now runing"); log.debug("Connecting " + this.webRtcEndpoints.size() + " webrtcendpoints"); // change the feed for all the webrtc clients connected. for (Entry<String, WebRtcEndpoint> ep : this.webRtcEndpoints.entrySet()) { this.crowdDetectorFilter.connect(ep.getValue()); } } public MediaPipeline getPipeline() { return this.pipe; } public List<RegionOfInterest> getRois() { return this.rois; } public void setWebRtcEndpoint(String session, WebRtcEndpoint webRtcEndpoint) { this.webRtcEndpoints.put(session, webRtcEndpoint); } public void removeWebRtcEndpoint(String session) { if (this.webRtcEndpoints.containsKey(session)) { this.webRtcEndpoints.get(session).release(); this.webRtcEndpoints.remove(session); log.debug("client removed"); } } public boolean isPlaying() { return this.playing; } public void addCandidate(IceCandidate candidate, String session) { WebRtcEndpoint endpoint = this.webRtcEndpoints.get(session); if (endpoint != null) { endpoint.addIceCandidate(candidate); } } }