org.kurento.demo.Pipeline.java Source code

Java tutorial

Introduction

Here is the source code for org.kurento.demo.Pipeline.java

Source

/*
 * (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);
        }
    }
}