diff --git a/frontend/src/composables/useLiveKitRoom.ts b/frontend/src/composables/useLiveKitRoom.ts index c2d7d82..643f51d 100644 --- a/frontend/src/composables/useLiveKitRoom.ts +++ b/frontend/src/composables/useLiveKitRoom.ts @@ -17,6 +17,8 @@ export function useLiveKitRoom() { const micEnabled = ref(false) const camEnabled = ref(false) const errorMsg = ref(null) + // 크게 보기(stage)로 승격된 참여자 identity. 진행자가 데이터 채널로 브로드캐스트 → 전원 동기화. + const featuredIdentity = ref(null) // 로컬 + 원격 참여자 목록 갱신(진행자 화면 구성은 단계 3에서 고도화) function refresh() { @@ -34,6 +36,33 @@ export function useLiveKitRoom() { function onDisconnected() { connected.value = false participants.value = [] + featuredIdentity.value = null + } + + // 데이터 채널 수신 — 진행자의 승격(promote) 메시지를 받아 featured 갱신 + function onData(payload: Uint8Array) { + try { + const msg = JSON.parse(new TextDecoder().decode(payload)) as { + type?: string + identity?: string + } + if (msg.type === 'promote' && typeof msg.identity === 'string') { + featuredIdentity.value = msg.identity + } + } catch { + // 알 수 없는 메시지는 무시 + } + } + + // 특정 참여자를 크게 보기로 승격 — 진행자만 호출(UI에서 제한). 전원에게 브로드캐스트. + async function promote(identity: string): Promise { + const r = room.value + if (!r) return + featuredIdentity.value = identity + const data = new TextEncoder().encode( + JSON.stringify({ type: 'promote', identity }), + ) + await r.localParticipant.publishData(data, { reliable: true }) } // 방 입장 — 토큰으로 연결 후 카메라/마이크 발행 @@ -49,6 +78,7 @@ export function useLiveKitRoom() { .on(RoomEvent.TrackUnsubscribed, refresh) .on(RoomEvent.LocalTrackPublished, refresh) .on(RoomEvent.LocalTrackUnpublished, refresh) + .on(RoomEvent.DataReceived, onData) .on(RoomEvent.Disconnected, onDisconnected) await r.connect(LIVEKIT_URL, token) @@ -82,6 +112,7 @@ export function useLiveKitRoom() { camEnabled.value = false micEnabled.value = false participants.value = [] + featuredIdentity.value = null } async function toggleMic(): Promise { @@ -106,9 +137,11 @@ export function useLiveKitRoom() { micEnabled, camEnabled, errorMsg, + featuredIdentity, connect, disconnect, toggleMic, toggleCam, + promote, } } diff --git a/frontend/src/pages/relay/MeetingPage.vue b/frontend/src/pages/relay/MeetingPage.vue index a4c975c..8570976 100644 --- a/frontend/src/pages/relay/MeetingPage.vue +++ b/frontend/src/pages/relay/MeetingPage.vue @@ -1,8 +1,9 @@