logo
On this page

PK battles

Prerequisites

Warning

Before you begin, make sure you complete the following:

  • Follow the integration steps by referring to the Quick start with co-hosting.

  • Please contact technical support to activate the Stream Mixing service.

What’s PK battles?

PK battle is a friendly competition between two live streams where audiences can see the engaged interactions between both hosts.

Quick start

Hosts can send a PK battle request to the host they want to connect with after they started their own live streams. And both live streams will be connected upon the PK battle request being accepted.

Start the PK battle

To start a PK battle, you will need to call the ZegoLiveStreamingManager.getInstance().sendPKBattleRequest(anotherHostUserID); method to send a PK battle request first. Once the host accepts your request, the PK battle starts.

Untitled
ZegoLiveStreamingManager.getInstance().sendPKBattleRequest(targetUserID, new UserRequestCallback() {
  @Override
  public void onUserRequestSend(int errorCode, String requestID) {
      if (errorCode != 0) {
        showTopTips(getContext().getString(R.string.livestreaming_send_pk_error, errorCode),false);
      }
      updateUI();
  }
});
1
Copied!

Stop the PK battle

To stop the PK battle, call the ZegoLiveStreamingManager.getInstance().stopPKBattle() method.

Listen to PK battle Events

To listen to PK battle events,call the ZegoLiveStreamingManager.getInstance().addLiveStreamingListener() method.In general, when you receive a PK request, you can display a pop-up window for the user to choose whether to accept or reject.if accept,call ZegoLiveStreamingManager.getInstance().acceptIncomingPKBattleRequest(),if reject, call ZegoLiveStreamingManager.getInstance().rejectPKBattleStartRequest(),You can also customize your own business logic to handle the corresponding PK event.

Untitled
ZegoLiveStreamingManager.getInstance().addLiveStreamingListener(new ZegoLiveStreamingListener() {
  @Override
  public void onIncomingPKBattleRequestReceived(String requestID, ZegoUIKitUser anotherHostUser, String anotherHostLiveID,String customData) {
        if (startPKDialog != null && startPKDialog.isShowing()) {
            return;
        }
        AlertDialog.Builder startPKBuilder = new AlertDialog.Builder(LiveActivity.this);
        //...
        startPKDialog = startPKBuilder.create();
        startPKDialog.setCanceledOnTouchOutside(false);
        startPKDialog.show();
  }
});
1
Copied!

Demo source code

For a detailed demo source code, click here.

To customize your own PK battle logic and process as needed, the ZegoLiveStreamingManager contains a bunch of methods for you to do further customizations. Before you make your customization, check the method intro part first.

Method intro

Send a PK battle request

Untitled
public void sendPKBattleRequest(String anotherHostUserID,int timeout,String customData, UserRequestCallback callback) 
1
Copied!
  • anotherHostUserID: to send a PK battle request, you will need to specify the user ID of the host you want to connect with. Remember the host you invite must has started a live stream, otherwise, an error will return via the method you called. For the error info and cause, check it in the callback.

  • timeout: this can be used to set the timeout duration of the PK battle request you sent. After it timed out, the host who sent the request will receive a callback notification via the ZegoLiveStreamingListener.onOutgoingPKBattleRequestTimeout.

  • customData: this can be used to customize the info that you want the host you invited to receive, and the invited host will receive the info you set via ZegoLiveStreamingListener.onIncomingPKBattleRequestReceived.

Sample code:

Untitled
ZegoLiveStreamingManager.getInstance().sendPKBattleRequest(targetUserID, new UserRequestCallback() {
  @Override
  public void onUserRequestSend(int errorCode, String requestID) {
      if (errorCode != 0) {
        showTopTips(getContext().getString(R.string.livestreaming_send_pk_error, errorCode),false);
      }
      updateUI();
  }
});
1
Copied!

Cancel the PK battle request

Untitled
ZegoLiveStreamingManager.getInstance().cancelPKBattleRequest(String customData,UserRequestCallback callback);
1
Copied!

The PK battle request can be canceled by calling this method when the request is not timed out and the request didn't get any responses. After it has been canceled, the invited host will receive a callback notification via the ZegoLiveStreamingListener.onIncomingPKBattleRequestCancelled.

Sample code:

Untitled
ZegoLiveStreamingManager.getInstance().cancelPKBattleRequest(new UserRequestCallback() {
  @Override
  public void onUserRequestSend(int errorCode, String requestID) {
      updateUI();
  }
});
1
Copied!

Respond to the PK battle request

To receive a PK battle request, you can listen to and set up the ZegoLiveStreamingListener.onIncomingPKBattleRequestReceived.

Accept the PK battle request

To accept the PK battle request, call the acceptIncomingPKBattleRequest method. And the peer host will receive notification via the onOutgoingPKBattleRequestAccepted, more details can be checked in PK request is accepted.

Untitled
ZegoLiveStreamingManager.getInstance().acceptIncomingPKBattleRequest(requestID, anotherHostLiveID, anotherHostUser);
1
Copied!

Reject the PK battle request

To reject the PK battle request, call the rejectIncomingPKBattleRequest method. And the peer host will receive notification via the onOutgoingPKBattleRequestRejected, and can tell why the request was rejected through the rejectCode. More details can be checked in PK request is rejected.

Untitled
ZegoLiveStreamingManager.getInstance().rejectPKBattleStartRequest(requestID);
1
Copied!

Sample code for responding to the PK request

Untitled
@Override
public void onIncomingPKBattleRequestReceived(String requestID, ZegoUIKitUser anotherHostUser,
    String anotherHostLiveID, String customData) {
    if (startPKDialog != null && startPKDialog.isShowing()) {
        return;
    }
    AlertDialog.Builder startPKBuilder = new AlertDialog.Builder(LiveActivity.this);
    startPKBuilder.setTitle(
        getString(com.zegocloud.uikit.prebuilt.livestreaming.R.string.livestreaming_invite_pk_title,
            anotherHostUser.userName));
    startPKBuilder.setPositiveButton(com.zegocloud.uikit.prebuilt.livestreaming.R.string.livestreaming_ok,
        new OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
                ZegoLiveStreamingManager.getInstance()
                    .acceptIncomingPKBattleRequest(requestID, anotherHostLiveID, anotherHostUser);
            }
        });
    startPKBuilder.setNegativeButton(
        com.zegocloud.uikit.prebuilt.livestreaming.R.string.livestreaming_disagree, new OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
                ZegoLiveStreamingManager.getInstance().rejectPKBattleStartRequest(requestID);
            }
        });
    startPKDialog = startPKBuilder.create();
    startPKDialog.setCanceledOnTouchOutside(false);
    startPKDialog.show();
}
1
Copied!

Listen to the sent PK battle request

PK battle request is accepted

When the sent PK battle request is accepted, you can receive callback notifications or customize your business logic by listening to or setting up the ZegoLiveStreamingListener.onOutgoingPKBattleRequestAccepted.

Untitled
  @Override
  public void onOutgoingPKBattleRequestAccepted(String anotherHostLiveID, ZegoUIKitUser anotherHostUser) {
    ZegoLiveStreamingManager.getInstance().startPKBattleWith(anotherHostLiveID, anotherHostUser.userID, anotherHostUser.userName);
  }
1
Copied!

PK battle request is rejected

When the sent PK battle request is rejected, You can receive callback notifications or customize your business logic by listening to or setting up the ZegoLiveStreamingListener.onOutgoingPKBattleRequestRejected.

Note

The PK battle request will be rejected automatically when the invited host is in a busy state. Busy state: the host has not initiated his live stream yet, the host is in a PK battle with others, the host is being invited, and the host is sending a PK battle request to others.

Untitled
@Override
public void onOutgoingPKBattleRequestRejected(int reason,ZegoUIKitUser anotherHostUser) {
    updateUI();
    if (reason == ZegoLiveStreamingPKBattleRejectCode.HOST_REJECT.ordinal()) {
        ZegoLiveStreamingManager.getInstance()
            .showTopTips(getContext().getString(R.string.livestreaming_send_pk_rejected), false);
    }else {
        ZegoLiveStreamingManager.getInstance()
            .showTopTips(getContext().getString(R.string.livestreaming_send_pk_busy), false);
    }
}
1
Copied!

Among which, the ZegoLiveStreamingPKBattleRejectCode can use to declare why the invited host rejected your request, the definition is as follows:

Untitled
public enum ZegoLiveStreamingPKBattleRejectCode {
    HOST_REJECT, USER_NOT_HOST, IN_PK, LIVE_NOT_STARTED, ALREADY_SEND, ALREADY_RECEIVED
}

1
Copied!

PK battle request is time out

If the invited host didn't respond after the timeout duration, the PK battle request timed out by default. While the Live Streaming Kit updates the internal state while won't trigger any default behaviors. You can receive callback notifications or customize your business logic by listening to or setting up the ZegoLiveStreamingListener.onOutgoingPKBattleRequestTimeout.

Sample code:

Untitled
@Override
public void onOutgoingPKBattleRequestTimeout(String requestID, ZegoUIKitUser anotherHost) {
    updateUI();
    ZegoLiveStreamingManager.getInstance()
        .showTopTips(getContext().getString(R.string.livestreaming_send_pk_no_reply), false);
}
1
Copied!

PK battle request failed to be sent

In some cases, PK battle requests can't be sent successfully, for example, the host's app is not started. And the sendPKBattleRequest returns an error when the PK battle request failed to be sent, you can tell and handle these errors by the value returned by the sendPKBattleRequest.

Sample code:

Untitled
ZegoLiveStreamingManager.getInstance().sendPKBattleRequest(editText.getText().toString(), new UserRequestCallback() {
  @Override
  public void onUserRequestSend(int errorCode, String requestID) {
      if (errorCode != 0) {
          ZegoLiveStreamingManager.getInstance().showTopTips(
              getContext().getString(R.string.livestreaming_send_pk_error, errorCode),
              false);
      }
      updateUI();
  }
});
1
Copied!

Listen to received PK battle request

Receives a PK battle request

When receiving a PK battle request, You can receive callback notifications or customize your business logic by listening to or setting up the ZegoLiveStreamingListener.onIncomingPKBattleRequestReceived.

Sample code:

Untitled
 ZegoLiveStreamingManager.getInstance().addLiveStreamingListener(new ZegoLiveStreamingListener() {
  @Override
  public void onIncomingPKBattleRequestReceived(String requestID, ZegoUIKitUser anotherHostUser, String anotherHostLiveID,String customData) {
        if (startPKDialog != null && startPKDialog.isShowing()) {
            return;
        }
        AlertDialog.Builder startPKBuilder = new AlertDialog.Builder(LiveActivity.this);
        //...
        startPKDialog = startPKBuilder.create();
        startPKDialog.setCanceledOnTouchOutside(false);
        startPKDialog.show();
  }
});

1
Copied!

Received PK battle request has been canceled

You can receive callback notifications or customize your business logic by listening to or setting up the ZegoLiveStreamingListener.onIncomingPKBattleRequestCancelled when the PK battle request has been canceled.

Untitled
@Override
public void onIncomingPKBattleRequestCancelled(String requestID, ZegoUIKitUser anotherHostUser, String customData) {
    if (startPKDialog != null && startPKDialog.isShowing()) {
        startPKDialog.dismiss();
    }
}
1
Copied!

Received PK battle request is timed out

You can receive callback notifications or customize your business logic by listening to or setting up the ZegoLiveStreamingListener.onIncomingPKBattleRequestTimeout when the received PK battle request has timed out.

Sample code:

Untitled
@Override
public void onIncomingPKBattleRequestTimeout(String requestID, ZegoUIKitUser anotherHost) {
    if (startPKDialog != null && startPKDialog.isShowing()) {
        startPKDialog.dismiss();
    }
}
1
Copied!

Mute the peer host during the PK battle

When a PK battle starts, both hosts can mute the connected host during the battle as needed. And after the peer host has been muted, the audience can't hear the voice from the muted livestream.

Untitled
ZegoLiveStreamingManager.getInstance().muteAnotherHostAudio(boolean mute,ZegoUIKitCallback callback)
1
Copied!

And you can also get the mute state of the peer host via the ZegoLiveStreamingManager().getInstance().isAnotherHostMuted().

Sample code:

Untitled
boolean pkUserMuted = ZegoLiveStreamingManager.getInstance().isAnotherHostMuted();
ZegoLiveStreamingManager.getInstance().muteAnotherHostAudio(!pkUserMuted, new ZegoUIKitCallback() {
    @Override
    public void onResult(int errorCode) {
        updateButton();
    }
});
1
Copied!

Custom prebuilt UI

Customizable methods unique to the PK battle feature

In addition to the above-mentioned methods used for customization, the ZegoLiveStreamingPKBattleConfig in ZegoUIKitPrebuiltLiveStreamingConfig is provided for customizing some UI and features that are unique to the PK battle feature.

Untitled
class ZegoLiveStreamingPKBattleConfig {

  /// When the connected host gets offline due to exceptions, SDK defaults to show "Host is reconnecting".
  /// To customize the content that displays when the connected host gets offline, use the [hostReconnectingProvider].
  public ZegoLiveStreamingPKBattleViewProvider2 hostReconnectingProvider;

  /// To overlay custom components on the PKBattleView, use the [pkBattleViewForegroundProvider].  
   public ZegoLiveStreamingPKBattleViewProvider pkBattleViewForegroundProvider;

  /// To add custom components on the top of the PKBattleView, use the [pkBattleViewTopProvider]. 
  public ZegoLiveStreamingPKBattleViewProvider pkBattleViewTopProvider;

  /// To add custom components on the bottom of the PKBattleView, use the [pkBattleViewBottomProvider]. 
  public ZegoLiveStreamingPKBattleViewProvider pkBattleViewBottomProvider;
}
1
Copied!

Among these, the definition of the ZegoLiveStreamingPKBattleViewProvider and the ZegoLiveStreamingPKBattleViewBuilder are as follows:

Untitled
public interface ZegoLiveStreamingPKBattleViewProvider {

    View getView(ViewGroup parent, List<ZegoUIKitUser> uiKitUsers);
}

public interface ZegoLiveStreamingPKBattleViewProvider2 {

    View getView(ViewGroup parent, ZegoUIKitUser uiKitUsers);
}
1
Copied!

To be specific, if you want to place custom views above, below, and on top of PKView, you can check the following sample code as a reference:

Untitled
// ZegoUIKitPrebuiltLiveStreamingConfig
  config.pkBattleConfig.pkBattleViewBottomProvider = new ZegoLiveStreamingPKBattleViewProvider() {
      @Override
      public View getView(ViewGroup parent, List<ZegoUIKitUser> uiKitUsers) {
          View view = new View(parent.getContext());
          view.setBackgroundColor(Color.RED);
          DisplayMetrics displayMetrics = parent.getContext().getResources().getDisplayMetrics();
          view.setLayoutParams(new FrameLayout.LayoutParams(-1, Utils.dp2px(24, displayMetrics)));
          return view;
      }
  };
  config.pkBattleConfig.pkBattleViewTopProvider = new ZegoLiveStreamingPKBattleViewProvider() {
      @Override
      public View getView(ViewGroup parent, List<ZegoUIKitUser> uiKitUsers) {
          View view = new View(parent.getContext());
          view.setBackgroundColor(Color.RED);
          DisplayMetrics displayMetrics = parent.getContext().getResources().getDisplayMetrics();
          view.setLayoutParams(new FrameLayout.LayoutParams(-1, Utils.dp2px(24, displayMetrics)));
          return view;
      }
  };
  config.pkBattleConfig.pkBattleViewForegroundProvider = new ZegoLiveStreamingPKBattleViewProvider() {
      @Override
      public View getView(ViewGroup parent, List<ZegoUIKitUser> uiKitUsers) {
          View view = new View(parent.getContext());
          view.setBackgroundColor(Color.RED);
          DisplayMetrics displayMetrics = parent.getContext().getResources().getDisplayMetrics();
          FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(-1, Utils.dp2px(24, displayMetrics));
          params.topMargin = parent.getHeight() / 2;
          view.setLayoutParams(params);
          return view;
      }
  };
  config.pkBattleConfig.hostReconnectingProvider = new ZegoLiveStreamingPKBattleViewProvider2() {
      @Override
      public View getView(ViewGroup parent, ZegoUIKitUser uiKitUsers) {
          TextView textView = new TextView(LiveActivity.this);
          textView.setLayoutParams(new FrameLayout.LayoutParams(-1, -1));
          textView.setBackgroundColor(ContextCompat.getColor(LiveActivity.this,
              com.zegocloud.uikit.prebuilt.livestreaming.R.color.gray_444));
          textView.setGravity(Gravity.CENTER);
          textView.setTextColor(Color.WHITE);
          textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
          textView.setText("uiKitUsers:" + uiKitUsers.userName + " disconnected");
          return textView;
      }
  };
1
Copied!

The effect will be like this:

Demo source code