Co-hosting

Allow audience members to become co-hosts and publish their audio alongside the main host.

Co-host Flow

┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│   AUDIENCE   │ ──► │   REQUEST    │ ──► │   CO-HOST    │
│  (subscribe) │     │  (pending)   │     │  (publish)   │
└──────────────┘     └──────────────┘     └──────────────┘
                            │
                            ▼
                     Host Approves

1. Audience Requests to Co-host

// Check permission first
if (!hasRecordAudioPermission()) {
    requestRecordAudioPermission();
    return;
}

// Send request to host (via your backend/socket)
sendCoHostRequest(seatNumber);

2. Host Approves Request

// Host receives request and approves
public void onCoHostRequestReceived(String userId, String name, int seat) {
    showApprovalDialog(name, () -> {
        // Approve - notify requester
        sendCoHostApproval(userId, seat);
    });
}

3. Audience Upgrades to Co-host

// When approval received
public void onCoHostApproved(int seatNumber) {
    // Upgrade - starts publishing audio
    audioHelper.upgradeToCoHost();

    // Update UI
    updateSeatUI(seatNumber, myUserId, myName);
    showCoHostControls();
}

4. Co-host Steps Down

// Co-host wants to leave seat
public void onStepDownClick() {
    // Downgrade - stops publishing
    audioHelper.downgradeToAudience();

    // Update UI
    clearSeat(mySeatNumber);
    showAudienceControls();
}

Complete Example

public class AudioLiveActivity extends AppCompatActivity {
    private ConoStreamAudioHelper audioHelper;
    private boolean isCoHost = false;

    // Audience clicks on empty seat
    public void onSeatClick(int seatNumber) {
        if (!hasRecordAudioPermission()) {
            requestPermission(RECORD_AUDIO, () -> onSeatClick(seatNumber));
            return;
        }

        // Show request dialog
        showRequestDialog(() -> {
            sendCoHostRequest(seatNumber);
            showPendingUI();
        });
    }

    // Received approval from host
    public void onApprovalReceived(int seat) {
        audioHelper.upgradeToCoHost();
        isCoHost = true;

        // Show mute button, hide request button
        muteButton.setVisibility(View.VISIBLE);
        requestButton.setVisibility(View.GONE);
        stepDownButton.setVisibility(View.VISIBLE);
    }

    // Mute toggle
    public void onMuteClick() {
        boolean muted = manager.isMicrophoneMuted();
        manager.muteMicrophone(!muted);
        updateMuteIcon(!muted);
    }

    // Step down
    public void onStepDownClick() {
        audioHelper.downgradeToAudience();
        isCoHost = false;

        muteButton.setVisibility(View.GONE);
        requestButton.setVisibility(View.VISIBLE);
        stepDownButton.setVisibility(View.GONE);
    }
}

Permissions

Role Permissions Needed
Audience None (just watching/listening)
Co-host RECORD_AUDIO (when clicking seat)
Host RECORD_AUDIO, CAMERA (at start)
ℹ️

The request/approval flow is handled by your app's backend (socket, API, etc.). ConoStream only handles the audio publishing upgrade.