/** parse an acknowledge to a token sent, analyze for permissions, disconnect on error */
  protected void parseVideoTokenResponse(JSONArray arg) {
    // TODO dk: parse all the other things that come with the response? TURN
    // Server, etc?
    boolean success = false;
    String message = "";
    try {
      success = "success".equalsIgnoreCase(arg.getString(0));
      if (success) {
        JSONObject obj = arg.getJSONObject(1);
        boolean subscribe = false;
        boolean publish = false;
        if (obj.has("permissions")) {
          JSONObject permissions = obj.getJSONObject("permissions");
          subscribe = permissions.has("subscribe") && permissions.getBoolean("subscribe");
          publish = permissions.has("publish") && permissions.getBoolean("publish");
        }
        mPermissionSubscribe = subscribe;
        mPermissionPublish = publish;
      } else {
        message = arg.get(1).toString();
      }
    } catch (JSONException e) {
      log(e.getMessage());
    }

    if (!success) {
      log("Token failed: " + message);
      disconnect();
    }
  }
 /**
  * decodes a video token into a string which can then be turned into a json object, returns null
  * on errors
  */
 private static final String decodeToken(String result) {
   try {
     String token = new String(Base64.decode(result.getBytes(), Base64.DEFAULT), "UTF-8");
     log("Licode token decoded: " + token);
     return token;
   } catch (UnsupportedEncodingException e) {
     log("Failed to decode token: " + e.getMessage());
   }
   return null;
 }
        @Override
        public void onEvent(JSONArray args, Acknowledge ack) {
          log("mOnDataStream");

          try {
            JSONObject param = args.getJSONObject(0);
            String streamId = param.getString("id");
            String message = param.getString("msg");
            StreamDescriptionInterface stream = mRemoteStream.get(streamId);
            for (RoomObserver obs : mObservers) {
              obs.onStreamData(message, stream);
            }
          } catch (JSONException e) {
          }
        }
        @Override
        public void onEvent(JSONArray args, Acknowledge ack) {
          // [{"data":true,"id":331051653483882560,"screen":"","audio":true,"video":true}]
          log("mOnAddStream");

          try {
            StreamDescription stream = StreamDescription.parseJson(args.getJSONObject(0));

            boolean isLocal = mLocalStream.get(stream.getId()) != null;
            if (!isLocal) {
              mRemoteStream.put(stream.getId(), stream);
              triggerStreamAdded(stream);
            }
          } catch (JSONException e) {
          }
        }
 /** get access to the camera */
 private VideoCapturer getVideoCapturer() {
   String[] cameraFacing = {"front", "back"};
   int[] cameraIndex = {0, 1};
   int[] cameraOrientation = {0, 90, 180, 270};
   for (String facing : cameraFacing) {
     for (int index : cameraIndex) {
       for (int orientation : cameraOrientation) {
         String name = "Camera " + index + ", Facing " + facing + ", Orientation " + orientation;
         VideoCapturer capturer = VideoCapturer.create(name);
         if (capturer != null) {
           log("Using camera: " + name);
           return capturer;
         }
       }
     }
   }
   throw new RuntimeException("Failed to open capturer");
 }
        @Override
        public void onEvent(JSONArray args, Acknowledge ack) {
          // [{"id":331051653483882560}]
          log("mOnRemoveStream");

          try {
            JSONObject param = args.getJSONObject(0);
            String streamId = param.getString("id");
            StreamDescription stream = (StreamDescription) mRemoteStream.get(streamId);

            if (stream != null) {
              removeStream(stream);
              mRemoteStream.remove(streamId);
              triggerStreamRemoved(stream);
            }
          } catch (JSONException e) {
          }
        }
 @Override
 public void onEvent(JSONArray args, Acknowledge ack) {
   log("mDisconnect");
   disconnect();
 }