@Override
  public void next(final ResponseListener<Object> listener) {
    int requestIdNumber = getNextId();
    final String requestId = String.format(Locale.US, "req%d", requestIdNumber);

    JSONObject message = null;
    try {
      message =
          new JSONObject() {
            {
              put("contentType", namespaceKey + "mediaCommand");
              put(
                  "mediaCommand",
                  new JSONObject() {
                    {
                      put("type", "playNext");
                      put("requestId", requestId);
                    }
                  });
            }
          };
    } catch (JSONException e) {
      Util.postError(listener, new ServiceCommandError(0, "JSON Parse error", null));
      return;
    }

    ServiceCommand<ResponseListener<Object>> command =
        new ServiceCommand<ResponseListener<Object>>(null, null, null, listener);
    mActiveCommands.put(requestId, command);
    sendMessage(message, listener);
  }
  public void handleMediaEvent(JSONObject payload) {
    String type = payload.optString("type");
    if (type.length() == 0) {
      String errorMsg = payload.optString("error");

      if (errorMsg.length() == 0) {
        return;
      } else {
        Log.w(Util.T, "Play State Error: " + errorMsg);
        if (mPlayStateSubscription != null) {
          for (PlayStateListener listener : mPlayStateSubscription.getListeners()) {
            Util.postError(listener, new ServiceCommandError(errorMsg));
          }
        }
      }
    }

    if (type.equals("playState")) {
      if (mPlayStateSubscription == null) return;

      String playStateString = payload.optString(type);
      if (playStateString.length() == 0) return;

      final MediaControl.PlayStateStatus playState = parsePlayState(playStateString);

      for (PlayStateListener listener : mPlayStateSubscription.getListeners()) {
        Util.postSuccess(listener, playState);
      }
    }
  }
  @Override
  public void playMedia(
      final MediaInfo mediaInfo,
      final boolean shouldLoop,
      final MediaPlayer.LaunchListener listener) {
    int requestIdNumber = getNextId();
    final String requestId = String.format(Locale.US, "req%d", requestIdNumber);
    JSONObject message = null;
    ImageInfo iconImage = null;
    List<ImageInfo> images = mediaInfo.getImages();

    if (images != null && !images.isEmpty()) {
      iconImage = images.get(0);
    }

    final String iconSrc = iconImage == null ? null : iconImage.getUrl();
    final SubtitleInfo subtitleInfo = mediaInfo.getSubtitleInfo();

    try {
      message = createPlayMediaJsonRequest(mediaInfo, shouldLoop, requestId, iconSrc, subtitleInfo);
    } catch (JSONException e) {
      Util.postError(listener, new ServiceCommandError(0, "JSON Parse error", null));
      return;
    }

    ResponseListener<Object> response =
        new ResponseListener<Object>() {

          @Override
          public void onError(ServiceCommandError error) {
            Util.postError(listener, error);
          }

          @Override
          public void onSuccess(Object object) {
            Util.postSuccess(
                listener,
                new MediaLaunchObject(launchSession, getMediaControl(), getPlaylistControl()));
          }
        };

    ServiceCommand<ResponseListener<Object>> command =
        new ServiceCommand<ResponseListener<Object>>(null, null, null, response);

    mActiveCommands.put(requestId, command);

    sendMessage(
        message,
        new ResponseListener<Object>() {

          @Override
          public void onError(ServiceCommandError error) {
            Util.postError(listener, error);
          }

          @Override
          public void onSuccess(Object object) {}
        });
  }
  @Override
  public void sendMessage(final JSONObject message, final ResponseListener<Object> listener) {
    if (message == null || message.length() == 0) {
      Util.postError(listener, new ServiceCommandError(0, "Cannot send an Empty Message", null));
      return;
    }

    sendP2PMessage(message, listener);
  }
  @SuppressWarnings("unchecked")
  public void handleMediaCommandResponse(final JSONObject payload) {
    String requestID = payload.optString("requestId");
    if (requestID.length() == 0) return;

    final ServiceCommand<ResponseListener<Object>> command =
        (ServiceCommand<ResponseListener<Object>>) mActiveCommands.get(requestID);

    if (command == null) return;

    String mError = payload.optString("error");

    if (mError.length() != 0) {
      Util.postError(command.getResponseListener(), new ServiceCommandError(0, mError, null));
    } else {
      Util.postSuccess(command.getResponseListener(), payload);
    }

    mActiveCommands.remove(requestID);
  }
  @Override
  public void displayImage(
      final String url,
      final String mimeType,
      final String title,
      final String description,
      final String iconSrc,
      final MediaPlayer.LaunchListener listener) {
    int requestIdNumber = getNextId();
    final String requestId = String.format(Locale.US, "req%d", requestIdNumber);

    JSONObject message = null;
    try {
      message =
          new JSONObject() {
            {
              putOpt("contentType", namespaceKey + "mediaCommand");
              putOpt(
                  "mediaCommand",
                  new JSONObject() {
                    {
                      putOpt("type", "displayImage");
                      putOpt("mediaURL", url);
                      putOpt("iconURL", iconSrc);
                      putOpt("title", title);
                      putOpt("description", description);
                      putOpt("mimeType", mimeType);
                      putOpt("requestId", requestId);
                    }
                  });
            }
          };
    } catch (JSONException e) {
      Util.postError(listener, new ServiceCommandError(0, "JSON Parse error", null));
      return;
    }

    ResponseListener<Object> response =
        new ResponseListener<Object>() {

          @Override
          public void onError(ServiceCommandError error) {
            Util.postError(listener, error);
          }

          @Override
          public void onSuccess(Object object) {
            Util.postSuccess(listener, new MediaLaunchObject(launchSession, getMediaControl()));
          }
        };

    ServiceCommand<ResponseListener<Object>> command =
        new ServiceCommand<ResponseListener<Object>>(socket, null, null, response);

    mActiveCommands.put(requestId, command);

    sendP2PMessage(
        message,
        new ResponseListener<Object>() {

          @Override
          public void onError(ServiceCommandError error) {
            Util.postError(listener, error);
          }

          @Override
          public void onSuccess(Object object) {}
        });
  }
  @Override
  public void getPlayState(final PlayStateListener listener) {
    int requestIdNumber = getNextId();
    final String requestId = String.format(Locale.US, "req%d", requestIdNumber);

    JSONObject message = null;
    try {
      message =
          new JSONObject() {
            {
              put("contentType", namespaceKey + "mediaCommand");
              put(
                  "mediaCommand",
                  new JSONObject() {
                    {
                      put("type", "getPlayState");
                      put("requestId", requestId);
                    }
                  });
            }
          };
    } catch (JSONException e) {
      Util.postError(listener, new ServiceCommandError(0, "JSON Parse error", null));
    }

    ServiceCommand<ResponseListener<Object>> command =
        new ServiceCommand<ResponseListener<Object>>(
            null,
            null,
            null,
            new ResponseListener<Object>() {

              @Override
              public void onSuccess(Object response) {
                try {
                  String playStateString = ((JSONObject) response).getString("playState");
                  PlayStateStatus playState = parsePlayState(playStateString);
                  Util.postSuccess(listener, playState);
                } catch (JSONException e) {
                  this.onError(new ServiceCommandError(0, "JSON Parse error", null));
                }
              }

              @Override
              public void onError(ServiceCommandError error) {
                Util.postError(listener, error);
              }
            });

    mActiveCommands.put(requestId, command);

    sendMessage(
        message,
        new ResponseListener<Object>() {

          @Override
          public void onSuccess(Object response) {}

          @Override
          public void onError(ServiceCommandError error) {
            Util.postError(listener, error);
          }
        });
  }