PK Battles

PK (Player Kill) battles allow two hosts to compete in a split-screen view. Each host's audience can see both streams side by side.

PK Architecture

┌──────────────────────────────────────────────────────┐
│                    PK BATTLE VIEW                     │
├─────────────────────────┬────────────────────────────┤
│                         │                            │
│      HOST A (LEFT)      │      HOST B (RIGHT)        │
│     (Your Room)         │    (Opponent Room)         │
│                         │                            │
├─────────────────────────┴────────────────────────────┤
│        Points: 1,500     VS     Points: 1,200        │
└──────────────────────────────────────────────────────┘

How It Works

  1. Each host is in their own room with their audience
  2. When PK starts, each host joins the opponent's room as subscriber
  3. UI switches to split-screen showing both hosts
  4. Audience in each room sees both hosts

Start PK Battle

// 1. Get opponent's room info from your backend
String opponentUrl = pkData.getOpponentServerUrl();
String opponentToken = pkData.getOpponentToken();
String opponentChannel = pkData.getOpponentChannelName();

// 2. Switch UI to PK layout
pkLayout.setVisibility(View.VISIBLE);
normalLayout.setVisibility(View.GONE);

// 3. Initialize PK renderers
initPkRenderers();

// 4. Attach local video to LEFT side
videoHelper.attachLocalVideoToPkView(pkLeftRenderer);

// 5. Join opponent's room
videoHelper.joinPkOpponentRoom(opponentUrl, opponentToken, opponentChannel);

// 6. Set up callback for opponent video
videoHelper.setPkOpponentCallback(new PkOpponentCallback() {
    @Override
    public void onPkOpponentVideoReceived(VideoTrack track) {
        runOnUiThread(() -> {
            track.addRenderer(pkRightRenderer);
        });
    }

    @Override
    public void onPkOpponentOffline(String name) {
        showOpponentOffline(name);
    }
});

// 7. Attach opponent video to RIGHT side
videoHelper.attachPkRemoteVideoToView(pkRightRenderer);

End PK Battle

// 1. Leave opponent's room
videoHelper.leavePkOpponentRoom();

// 2. Cleanup PK renderers
videoHelper.cleanupPkRenderers();

// 3. Switch back to normal layout
pkLayout.setVisibility(View.GONE);
normalLayout.setVisibility(View.VISIBLE);

// 4. Re-attach local video to normal view
videoHelper.attachLocalVideoToView(localVideoView);

PK Layout XML

<LinearLayout
    android:id="@+id/pk_layout"
    android:orientation="horizontal"
    android:visibility="gone">

    <!-- Left: Local host -->
    <FrameLayout
        android:layout_weight="1">
        <io.conostream.webrtc.TextureViewRenderer
            android:id="@+id/pk_left" />
    </FrameLayout>

    <!-- Divider -->
    <View android:layout_width="2dp" android:background="#FFF" />

    <!-- Right: Opponent -->
    <FrameLayout
        android:layout_weight="1">
        <io.conostream.webrtc.TextureViewRenderer
            android:id="@+id/pk_right" />
        <TextView
            android:id="@+id/pk_opponent_offline"
            android:text="Opponent Offline"
            android:visibility="gone" />
    </FrameLayout>
</LinearLayout>

Handle Opponent Offline

videoHelper.setPkOpponentCallback(new PkOpponentCallback() {
    @Override
    public void onPkOpponentOffline(String name) {
        runOnUiThread(() -> {
            pkOpponentOfflineText.setText(name + " offline");
            pkOpponentOfflineText.setVisibility(View.VISIBLE);
        });
    }

    @Override
    public void onPkOpponentReconnected() {
        runOnUiThread(() -> {
            pkOpponentOfflineText.setVisibility(View.GONE);
        });
    }
});
ℹ️

PK scoring, timers, and winner determination are handled by your backend/app logic. ConoStream only handles the video streams.