type !== 'space') { return $fallbackRole; } if ($user && $user->ownerRef() === $room->host_user_ref) { return 'host'; } $speakerRefs = (array) $room->setting('speaker_refs', []); if ($user && in_array($user->ownerRef(), $speakerRefs, true)) { return 'panelist'; } return 'attendee'; } public function canPublish(Room $room, Participant $participant): bool { if ($room->type !== 'space') { return true; } return in_array($participant->role, ['host', 'co_host', 'panelist'], true); } public function isListener(Room $room, Participant $participant): bool { return $room->type === 'space' && $participant->role === 'attendee'; } public function isAudioOnly(Room $room): bool { return $room->isSpace() || (bool) $room->setting('audio_only', false); } /** * Whether a live-room feature is available for this room type. * Audio rooms (Spaces) mirror Twitter Spaces — no breakouts, chat, Q&A, etc. */ public function allowsRoomFeature(Room $room, string $feature): bool { if (! $room->isSpace()) { return true; } return ! in_array($feature, [ 'breakouts', 'chat', 'qa', 'polls', 'files', 'whiteboard', 'programme', 'live_stream', 'lock', ], true); } }