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

    log.debug("Incoming message: {}", jsonMessage);

    switch (jsonMessage.get("id").getAsString()) {
      case "start":
        start(session, jsonMessage);
        break;
      case "show_mouths":
        setVisualization(session, jsonMessage);
        break;
      case "scale_factor":
        log.debug("Case scale factor");
        setScaleFactor(session, jsonMessage);
        break;
      case "process_num_frames":
        log.debug("Case process num frames");
        setProcessNumberFrames(session, jsonMessage);
        break;
      case "width_to_process":
        log.debug("Case width to process");
        setWidthToProcess(session, jsonMessage);
        break;
      case "stop":
        {
          UserSession user = users.remove(session.getId());
          if (user != null) {
            user.release();
          }
          break;
        }
      case "onIceCandidate":
        {
          JsonObject candidate = jsonMessage.get("candidate").getAsJsonObject();

          UserSession user = users.get(session.getId());
          if (user != null) {
            IceCandidate cand =
                new IceCandidate(
                    candidate.get("candidate").getAsString(),
                    candidate.get("sdpMid").getAsString(),
                    candidate.get("sdpMLineIndex").getAsInt());
            user.addCandidate(cand);
          }
          break;
        }

      default:
        sendError(session, "Invalid message with id " + jsonMessage.get("id").getAsString());
        break;
    }
  }
  private void start(final WebSocketSession session, JsonObject jsonMessage) {
    try {
      // Media Logic (Media Pipeline and Elements)
      UserSession user = new UserSession();
      MediaPipeline pipeline = kurento.createMediaPipeline();
      user.setMediaPipeline(pipeline);
      WebRtcEndpoint webRtcEndpoint = new WebRtcEndpoint.Builder(pipeline).build();
      user.setWebRtcEndpoint(webRtcEndpoint);
      users.put(session.getId(), user);

      webRtcEndpoint.addOnIceCandidateListener(
          new EventListener<OnIceCandidateEvent>() {

            @Override
            public void onEvent(OnIceCandidateEvent event) {
              JsonObject response = new JsonObject();
              response.addProperty("id", "iceCandidate");
              response.add("candidate", JsonUtils.toJsonObject(event.getCandidate()));
              try {
                synchronized (session) {
                  session.sendMessage(new TextMessage(response.toString()));
                }
              } catch (IOException e) {
                log.debug(e.getMessage());
              }
            }
          });

      mouth = new NuboMouthDetector.Builder(pipeline).build();

      webRtcEndpoint.connect(mouth);
      mouth.connect(webRtcEndpoint);

      // SDP negotiation (offer and answer)
      String sdpOffer = jsonMessage.get("sdpOffer").getAsString();
      String sdpAnswer = webRtcEndpoint.processOffer(sdpOffer);

      // Sending response back to client
      JsonObject response = new JsonObject();
      response.addProperty("id", "startResponse");
      response.addProperty("sdpAnswer", sdpAnswer);

      synchronized (session) {
        session.sendMessage(new TextMessage(response.toString()));
      }
      webRtcEndpoint.gatherCandidates();

    } catch (Throwable t) {
      sendError(session, t.getMessage());
    }
  }