com.nttdata.emea.nuoffice.CallHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.nttdata.emea.nuoffice.CallHandler.java

Source

/*
 * (C) Copyright 2014 Kurento (http://kurento.org/)
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 */
package com.nttdata.emea.nuoffice;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.concurrent.ConcurrentHashMap;

import org.kurento.client.factory.KurentoClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.nttdata.emea.nuoffice.ffmpeg.Decoder;
import com.nttdata.emea.nuoffice.recognita.RecognitionService;
import com.nttdata.emea.nuoffice.scp.ScpFrom;

/**
 * Protocol handler for 1 to 1 video call communication.
 * 
 * @author Boni Garcia (bgarcia@gsyc.es)
 * @author Micael Gallego (micael.gallego@gmail.com)
 * @since 5.0.0
 */
public class CallHandler extends TextWebSocketHandler {

    private CallMediaPipeline pipeline;

    private static final Logger log = LoggerFactory.getLogger(CallHandler.class);
    private static final Gson gson = new GsonBuilder().create();

    private static final long DEFAULT_RECORD_PERIOD = 5000;

    private static final long DEFAULT_SAMPLE_PERIOD = 5000;

    private static final String DIR = "/tmp/";

    private ConcurrentHashMap<String, CallMediaPipeline> pipelines = new ConcurrentHashMap<String, CallMediaPipeline>();

    @Autowired
    private KurentoClient kurento;

    @Autowired
    private UserRegistry registry;

    @Autowired
    private RecognitionService recognitoService;

    public CallHandler() {
        super();
        File dir = new File(DIR + "");
        if (!dir.exists())
            dir.mkdirs();
    }

    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        JsonObject jsonMessage = gson.fromJson(message.getPayload(), JsonObject.class);
        UserSession user = registry.getBySession(session);

        if (user != null) {
            log.debug("Incoming message from user '{}': {}", user.getName(), jsonMessage);
        } else {
            log.debug("Incoming message from new user: {}", jsonMessage);
        }

        switch (jsonMessage.get("id").getAsString()) {
        case "register":
            register(session, jsonMessage);
            break;
        case "reset":
            reset(session, jsonMessage);
            break;
        case "call":
            call(user, jsonMessage);
            break;
        case "incomingCallResponse":
            incomingCallResponse(user, jsonMessage);
            break;
        case "startRecording":
            startRecording(session, jsonMessage);
            break;
        case "stopRecording":
            stopRecording(session, jsonMessage);
            break;
        case "addPrint":
            addPrint(session, jsonMessage);
            break;
        case "verifySample":
            verifySample(session, jsonMessage);
            break;
        case "play":
            play(session, jsonMessage);
            break;
        case "textChat":
            textChat(session, jsonMessage);
            break;
        case "cobrowsing":
            cobrowsing(session, jsonMessage);
            break;
        case "stop":
            stop(session);
            break;
        default:
            break;
        }
    }

    private void startRecording(WebSocketSession session, JsonObject jsonMessage) throws IOException {
        JsonObject response = new JsonObject();
        String user = jsonMessage.getAsJsonPrimitive("user").getAsString();
        String responseMsg = "accepted";
        pipeline.startDefaultRecording();
        response.addProperty("id", "startRecording");
        response.addProperty("response", responseMsg);
        UserSession us = new UserSession(session, user);
        us.sendMessage(response);
    }

    private void stopRecording(WebSocketSession session, JsonObject jsonMessage) throws IOException {
        try {

            log.debug("System library path = " + System.getProperty("java.library.path"));
            JsonObject response = new JsonObject();
            String user = jsonMessage.getAsJsonPrimitive("user").getAsString();
            pipeline.stopDefaultRecording();
            String responseMsg = "accepted";
            response.addProperty("id", "stopRecording");
            response.addProperty("response", responseMsg);
            UserSession us = new UserSession(session, user);
            us.sendMessage(response);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void addPrint(WebSocketSession session, JsonObject jsonMessage) throws IOException {
        try {
            JsonObject response = new JsonObject();
            String user = jsonMessage.getAsJsonPrimitive("user").getAsString();
            String caller = jsonMessage.getAsJsonPrimitive("caller").getAsString();
            long recordPeriod = DEFAULT_RECORD_PERIOD;
            try {
                recordPeriod = jsonMessage.getAsJsonPrimitive("recordPeriod").getAsLong();
            } catch (Exception e) {
            }
            log.debug("Record period = " + recordPeriod);
            log.debug("Start print recording");
            String recordId = pipeline.startRecording();
            Thread.sleep(recordPeriod);
            log.debug("Stop print recording");
            recordId = pipeline.stopRecording();

            log.debug("System library path = " + System.getProperty("java.library.path"));
            log.info("Read file " + recordId + ".webm from media server");
            new ScpFrom().read(new String[] {
                    "chris@" + NuOfficePrototypeApplication.IP_ADRESS + ":" + DIR + recordId + ".webm",
                    DIR + recordId + ".webm" });
            String printId = caller + "_" + recordId;
            new Decoder().process(DIR + recordId + ".webm", DIR + printId + ".wav");
            String responseMsg = "accepted";
            response.addProperty("id", "addPrint");
            response.addProperty("recordId", recordId);
            response.addProperty("printId", printId);
            response.addProperty("response", responseMsg);
            UserSession us = new UserSession(session, user);
            us.sendMessage(response);
            recognitoService.addPrint(printId, "c:/tmp/" + printId + ".wav");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void verifySample(WebSocketSession session, JsonObject jsonMessage) throws IOException {
        try {
            JsonObject response = new JsonObject();
            String user = jsonMessage.getAsJsonPrimitive("user").getAsString();
            long recordPeriod = DEFAULT_SAMPLE_PERIOD;
            try {
                recordPeriod = jsonMessage.getAsJsonPrimitive("recordPeriod").getAsLong();
            } catch (Exception e) {
            }
            String result = null;
            String recordId = null;
            int count = 0;
            do {
                log.debug("Record period = " + recordPeriod);
                log.debug("Start sample recording");
                recordId = pipeline.startRecording();
                Thread.sleep(recordPeriod);
                log.debug("Stop sample recording");
                recordId = pipeline.stopRecording();
                log.debug("System library path = " + System.getProperty("java.library.path"));
                log.info("Read file " + recordId + ".webm from media server");
                new ScpFrom().read(new String[] { "chris@localhost:/tmp/" + recordId + ".webm",
                        "c:/tmp/" + recordId + ".webm" });
                new Decoder().process("c:/tmp/" + recordId + ".webm", "c:/tmp/" + recordId + ".wav");
                result = recognitoService.verifySample(new File("c:/tmp/" + recordId + ".wav"));
                log.info(result + "identified as customer");
            } while (result == null && count++ < 1);
            String responseMsg = result != null ? result.split("_")[0] : "unknown";
            response.addProperty("id", "verifySample");
            response.addProperty("recordId", recordId);
            response.addProperty("response", responseMsg);
            UserSession us = new UserSession(session, user);
            us.sendMessage(response);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void register(WebSocketSession session, JsonObject jsonMessage) throws IOException {
        String name = jsonMessage.getAsJsonPrimitive("name").getAsString();
        if (name.equals("Agent")) {
            chat = new StringBuffer("Welcome to NTT DATA Textchat!");
        }
        boolean cobrowsing = jsonMessage.getAsJsonPrimitive("cobrowsing").getAsBoolean();
        UserSession caller = new UserSession(session, name, cobrowsing);
        String responseMsg = "accepted";
        if (name.isEmpty()) {
            responseMsg = "rejected: empty user name";
        } else if (registry.exists(name)) {
            responseMsg = "rejected: user '" + name + "' already registered";
        } else {
            registry.register(caller);
        }

        JsonObject response = new JsonObject();
        response.addProperty("id", "registerResponse");
        response.addProperty("response", responseMsg);
        caller.sendMessage(response);

        response = new JsonObject();
        response.addProperty("id", "textChat");
        response.addProperty("response", chat.toString());
        TextMessage tm = new TextMessage(response.toString());
        session.sendMessage(tm);

    }

    private void reset(WebSocketSession session, JsonObject jsonMessage) throws IOException {
        registry.reset();
        register(session, jsonMessage);
    }

    private void call(UserSession caller, JsonObject jsonMessage) throws IOException {
        String to = jsonMessage.get("to").getAsString();
        String from = jsonMessage.get("from").getAsString();
        JsonObject response = new JsonObject();

        if (registry.exists(to)) {
            UserSession callee = registry.getByName(to);
            caller.setSdpOffer(jsonMessage.getAsJsonPrimitive("sdpOffer").getAsString());
            caller.setCallingTo(to);

            response.addProperty("id", "incomingCall");
            response.addProperty("from", from);

            callee.sendMessage(response);
            callee.setCallingFrom(from);
        } else {
            response.addProperty("id", "callResponse");
            response.addProperty("response", "rejected: user '" + to + "' is not registered");

            caller.sendMessage(response);
        }
    }

    private void incomingCallResponse(UserSession callee, JsonObject jsonMessage) throws IOException {
        String callResponse = jsonMessage.get("callResponse").getAsString();
        String from = jsonMessage.get("from").getAsString();
        UserSession calleer = registry.getByName(from);
        String to = calleer.getCallingTo();

        if ("accept".equals(callResponse)) {
            log.debug("Accepted call from '{}' to '{}'", from, to);

            pipeline = new CallMediaPipeline(kurento, from, to);
            pipelines.put(calleer.getSessionId(), pipeline);
            pipelines.put(callee.getSessionId(), pipeline);

            String calleeSdpOffer = jsonMessage.get("sdpOffer").getAsString();
            String calleeSdpAnswer = pipeline.generateSdpAnswerForCallee(calleeSdpOffer);

            JsonObject startCommunication = new JsonObject();
            startCommunication.addProperty("id", "startCommunication");
            startCommunication.addProperty("sdpAnswer", calleeSdpAnswer);
            callee.sendMessage(startCommunication);

            String callerSdpOffer = registry.getByName(from).getSdpOffer();
            String callerSdpAnswer = pipeline.generateSdpAnswerForCaller(callerSdpOffer);

            JsonObject response = new JsonObject();
            response.addProperty("id", "callResponse");
            response.addProperty("response", "accepted");
            response.addProperty("sdpAnswer", callerSdpAnswer);
            calleer.sendMessage(response);

            // pipeline.record();

        } else {
            JsonObject response = new JsonObject();
            response.addProperty("id", "callResponse");
            response.addProperty("response", "rejected");
            calleer.sendMessage(response);
        }
    }

    public void cobrowsing(WebSocketSession session, JsonObject jsonMessage) throws IOException {
        for (UserSession s : registry.getCobrowsingSessions()) {
            log.info("receiving cobrowsing message");
            if (!s.getSessionId().equals(session.getId()))
                s.sendMessage(jsonMessage);
        }
    }

    public void stop(WebSocketSession session) throws IOException {
        String sessionId = session.getId();
        if (pipelines.containsKey(sessionId)) {
            pipelines.get(sessionId).release();
            pipelines.remove(sessionId);

            // Both users can stop the communication. A 'stopCommunication'
            // message will be sent to the other peer.
            UserSession stopperUser = registry.getBySession(session);
            UserSession stoppedUser = (stopperUser.getCallingFrom() != null)
                    ? registry.getByName(stopperUser.getCallingFrom())
                    : registry.getByName(stopperUser.getCallingTo());

            JsonObject message = new JsonObject();
            message.addProperty("id", "stopCommunication");
            stoppedUser.sendMessage(message);
        }
    }

    private void play(WebSocketSession session, JsonObject jsonMessage) throws IOException {
        String id = "LAST_SESSION";
        String recordId = (jsonMessage.get("recordId") != null
                && !jsonMessage.getAsJsonPrimitive("recordId").getAsString().isEmpty())
                        ? jsonMessage.get("recordId").getAsString()
                        : id;
        log.debug("Playing recorded call with id '{}'", recordId);
        PlayMediaPipeline pipeline = new PlayMediaPipeline(kurento, recordId, session);
        String sdpOffer = jsonMessage.get("sdpOffer").getAsString();
        String sdpAnswer = pipeline.generateSdpAnswer(sdpOffer);

        JsonObject response = new JsonObject();
        response.addProperty("id", "playResponse");
        response.addProperty("response", "accepted");
        response.addProperty("sdpAnswer", sdpAnswer);
        session.sendMessage(new TextMessage(response.toString()));

        pipeline.play();

    }

    private static final String newLine = System.getProperty("line.separator");

    private StringBuffer chat = new StringBuffer();

    private String addToChat(String user, String text) {
        if (chat.length() > 0)
            chat.append(newLine);
        return chat.append(user + ": ").append(text).toString();
    }

    private void textChat(WebSocketSession session, JsonObject jsonMessage) throws IOException {
        String user = jsonMessage.getAsJsonPrimitive("user").getAsString();
        JsonObject response = new JsonObject();
        response.addProperty("id", "textChat");
        String text = jsonMessage.getAsJsonPrimitive("input").getAsString();
        response.addProperty("response", addToChat(user, text));
        TextMessage tm = new TextMessage(response.toString());
        for (UserSession s : registry.getSessions()) {
            s.getSession().sendMessage(tm);
        }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        registry.removeBySession(session);
    }

}