How to Add a Host PK Feature in a Live Streaming App | Android Tutorial


Many popular live streaming platforms include a “PK” feature (short for “Player Kill” or “versus battle”), where hosts compete to receive gifts from viewers, and the host who gets the most gifts wins. In some cases, a last-second gift from a fan can overturn what seemed like a sure result, providing a thrilling experience for the audience. For the streaming platform, the PK feature typically grants hosts advanced permissions and is a key driver of engagement.
This article will guide you through integrating a PK feature into an Android live streaming app.
We’ll build upon an existing live streaming setup using Tencent RTC’s TUILiveKit component.
Custom Functionality
Custom Battle waiting countdown style
If you need the custom battle waiting countdown style, please refer to the following path for changes:
// File location: tuilivekit/src/main/java/com/trtc/uikit/livekit/view/liveroom/view/anchor/component/livestreaming/battle/
├── BattleCountdownBackView.java // Battle waiting countdown background style
└── BattleCountdownView.java // Battle waiting countdown foreground style
Custom Definition Dual Battle Score Style
If you need the custom Definition Dual battle score style, please refer to the following path for changes:
// File location: tuilivekit/src/main/java/com/trtc/uikit/livekit/view/liveroom/view/common/battle/SingleBattleScoreView.java
public class SingleBattleScoreView extends FrameLayout {
...
}
Custom Definition Multi Battle Score Style
If you need the custom Definition Multi Battle score style, please refer to the following path for changes:
// File location: tuilivekit/src/main/java/com/trtc/uikit/livekit/view/liveroom/view/common/battle/BattleMemberInfoView.java
public class BattleMemberInfoView extends FrameLayout {
...
}
Custom Definition Battle Score Result Style
If you need a Custom Definition Battle Score Result Style, please refer to the following path for changes:
// File location: tuilivekit/src/main/java/com/trtc/uikit/livekit/view/liveroom/view/common/battle/BattleInfoView.java
public class BattleInfoView extends BasicView {
...
private void showBattleResult(int type) {
// Battle Result Display
}
}
Key code
Anchor Battle
TUILiveKit Anchor battle feature is mainly based on BattleService
. You can obtain the battle management object through store.serviceCenter.battleService
and call the relevant battle API functions to implement the battle feature. For example, in the interaction between Anchor A and B, refer to the diagram below for the specific interaction sequence.
Anchor A initiates Battle
Anchor A initiates a battle by calling requestBattle
, passing the maximum Battle duration in parameter config
, whether the inviter needs to reply with accept/reject, and passing anchor B's userId in parameter userIdList
, and passing the battle invitation wait duration in parameter timeout
.
// File location: tuilivekit/src/main/java/com/trtc/uikit/livekit/manager/controller/BattleController.java
public void requestBattle(List<String> roomIdList, int timeout) {
TUILiveBattleManager.BattleConfig config = new TUILiveBattleManager.BattleConfig();
config.duration = BattleState.BATTLE_DURATION;
config.needResponse = mBattleState.mNeedResponse;
config.extensionInfo = "";
mLiveService.requestBattle(config, roomIdList, timeout, new TUILiveBattleManager.BattleRequestCallback() {
@Override
public void onSuccess(TUILiveBattleManager.BattleInfo battleInfo,
Map<String, TUILiveBattleManager.BattleCode> map) {
mBattleState.mBattleId = battleInfo.battleId;
mBattleState.mBattleConfig.copy(config);
List<BattleState.BattleUser> sendRequests = mBattleState.mSentBattleRequests.get();
for (Map.Entry<String, TUILiveBattleManager.BattleCode> entry : map.entrySet()) {
String key = entry.getKey();
TUILiveBattleManager.BattleCode code = entry.getValue();
if (code == TUILiveBattleManager.BattleCode.SUCCESS) {
for (ConnectionState.ConnectionUser user : mConnectionState.connectedUsers.get()) {
if (TextUtils.equals(user.userId, key)) {
sendRequests.add(new BattleState.BattleUser(user));
break;
}
}
} else {
notifyToast(convertCodeToString(entry.getValue()));
}
}
mBattleState.mSentBattleRequests.set(sendRequests);
}
@Override
public void onError(TUICommonDefine.Error error, String s) {
ErrorHandler.onError(error);
mBattleState.mSentBattleRequests.clear();
}
});
}
Anchor A can receive the request acceptance callback via onBattleRequestAccept
.
Anchor receives a battle request
Anchor B receives the battle request callback via onBattleRequestReceived
.
// File location: tuilivekit/src/main/java/com/trtc/uikit/livekit/manager/observer/LiveBattleManagerObserver.java
@Override
public void onBattleRequestReceived(BattleInfo battleInfo, BattleUser inviter, BattleUser invitee) {
LiveKitLog.info(mTag + " onBattleRequestReceived:[battleInfo:" + new Gson().toJson(battleInfo)
+ ", inviter:" + new Gson().toJson(inviter) + ", invitee:" + new Gson().toJson(invitee) + "]");
mBattleController.onBattleRequestReceived(battleInfo, inviter);
}
Anchor B accepts the battle request by calling acceptBattle
.
// File location: tuilivekit/src/main/java/com/trtc/uikit/livekit/manager/controller/BattleController.java
public void accept() {
mLiveService.acceptBattle(mBattleState.mBattleId, new TUIRoomDefine.ActionCallback() {
@Override
public void onSuccess() {
}
@Override
public void onError(TUICommonDefine.Error error, String s) {
}
});
}
Anchors A, B, and the audience in the room can receive the battle start callback through onBattleStarted
.
// File location: tuilivekit/src/main/java/com/trtc/uikit/livekit/manager/observer/LiveBattleManagerObserver.java
@Override
public void onBattleStarted(BattleInfo battleInfo) {
LiveKitLog.info(mTag + " onBattleStarted:[battleInfo:" + new Gson().toJson(battleInfo) + "]");
mBattleController.onBattleStarted(battleInfo);
}
The anchor exits the battle
For example, when anchor B exits the battle, the interaction sequence can be referenced from the diagram below.
Anchor B calls exitBattle
to exit the battle.
// File location: tuilivekit/src/main/java/com/trtc/uikit/livekit/manager/controller/BattleController.java
public void exitBattle() {
mLiveService.exitBattle(mBattleState.mBattleId, new TUIRoomDefine.ActionCallback() {
@Override
public void onSuccess() {
mBattleState.mSentBattleRequests.clear();
mBattleState.mBattledUsers.clear();
removeBattleRequestReceived();
}
@Override
public void onError(TUICommonDefine.Error error, String s) {
}
});
}
Anchors A, B, and the room audience receive the onBattleEnded
callback and the battle end notification.
// File location: tuilivekit/src/main/java/com/trtc/uikit/livekit/manager/observer/LiveBattleManagerObserver.java
@Override
public void onBattleEnded(BattleInfo battleInfo, BattleStoppedReason reason) {
LiveKitLog.info(mTag + " onBattleEnded:[battleInfo:"
+ new Gson().toJson(battleInfo) + ", reason:" + reason + "]");
mBattleController.onBattleEnded(battleInfo);
}
Now you can add a host PK feature to your live streaming app! For more details on additional features, please refer to the documentation.
My name is Susie. I am a writer and Media Service Product Manager. I work with startups across the globe to build real-time communication solutions using SDK and APIs.
If you want to build face filter or other special effect into your app, welcome to contact us.
Subscribe to my newsletter
Read articles from shuoxin wang directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
