블로그 목록
Tutorial8분 읽기

Agora RTC를 활용한 라이브스트리밍 구현하기 (쇼핑, 이벤트 등 활용)

호스트/시청자 역할과 Agora Web SDK를 사용해 라이브 스트리밍을 구현하는 방법을 단계별로 알아봅니다. 쇼핑 라이브, 웨비나, 이벤트 방송에 활용할 수 있습니다.

AgoraRTCLive Streaming호스트시청자

Agora RTC의 라이브 스트리밍(Live) 모드를 사용하면 호스트가 방송하고 시청자가 시청하는 구조의 서비스를 만들 수 있습니다. 쇼핑 라이브, 웨비나, 온라인 이벤트, 교육 방송 등에 적합합니다. 이 글에서는 mode: "live"와 호스트/시청자 역할을 활용해 라이브 스트리밍을 구현하는 방법을 단계별로 정리합니다.

라이브 스트리밍이란? (쇼핑·이벤트 활용)

일반 화상 통화(RTC) 는 채널에 들어온 모든 참가자가 동일한 권한으로 영상·음성을 보내고 받습니다. 반면 라이브 스트리밍은 다음처럼 역할이 나뉩니다.

  • 호스트(Host): 방송을 진행하는 쪽. 마이크·카메라(또는 화면 공유)를 퍼블리시하고, 시청자에게 전달됩니다. 여러 명이 호스트로 입장하면 코호스트 형태로 함께 방송할 수 있습니다.
  • 시청자(Audience): 방송을 보는 쪽. 호스트(및 코호스트)의 스트림만 구독하며, 자신은 영상·음성을 퍼블리시하지 않습니다.

이 구조는 라이브 커머스(쇼핑 라이브), 웨비나, 온라인 이벤트, 교육 방송 등에 그대로 적용할 수 있습니다. 프로젝트의 app/agora-demo/live-streaming/page.tsx는 이 모드를 사용한 데모입니다.

RTC 통화 모드와의 차이

항목RTC 통화 (mode: "rtc")라이브 스트리밍 (mode: "live")
역할없음 (전원 동일)host / audience
퍼블리시입장한 모든 참가자 가능호스트만 가능
시청자-영상·음성 퍼블리시 불가, 구독만

라이브 스트리밍에서는 입장 전에 역할(호스트/시청자) 을 정하고, setClientRole(role) 로 설정한 뒤 join 합니다.

준비 사항

  • Agora 콘솔: App ID, App Certificate
  • 토큰 서버: RTC 채널 토큰, RTM 사용자 토큰(채팅·시그널링용)을 각각 백엔드에서 발급
  • 패키지: agora-rtc-sdk-ng, agora-rtm-sdk (채팅·손들기·참가자 수 등)

전체 흐름 요약

  1. 클라이언트 생성mode: "live", 코덱 설정
  2. 역할 설정client.setClientRole("host" | "audience")
  3. 채널 입장client.join(appId, channelName, token, uid)
  4. 호스트만 로컬 트랙 생성 후 client.publish()
  5. 원격 사용자 구독user-publishedsubscribetrack.play()
  6. 채팅·시그널링·참가자 수 → RTM으로 보완
  7. 퇴장client.leave(), 트랙 정리, RTM logout()

1. 클라이언트 생성 및 역할 설정

라이브 스트리밍용 클라이언트는 mode: "live" 로 생성합니다. 입장 전에 역할을 설정해야 합니다.

import AgoraRTC from "agora-rtc-sdk-ng";

const client = AgoraRTC.createClient({ mode: "live", codec: "vp8" });

// 호스트: 방송 진행 / 시청자: 시청만
await client.setClientRole(role); // "host" | "audience"

const token = await fetch(
  `${TOKEN_API}?channel=${encodeURIComponent(channelName)}&uid=${requestUid}`
).then((res) => res.json()).then((data) => data.token);

const uid = await client.join(APP_ID, channelName, token, requestUid);
  • UI에서 입장 전에 "호스트(방송)" / "시청자" 를 선택하고, 선택한 값을 setClientRole 에 넘기면 됩니다.

2. 호스트: 로컬 트랙 퍼블리시

호스트만 마이크·카메라 트랙을 만들고 퍼블리시합니다. 시청자는 퍼블리시하지 않으므로 트랙 생성 코드를 역할에 따라 분기합니다.

if (role === "host") {
  const [audioTrack, videoTrack] = await Promise.all([
    AgoraRTC.createMicrophoneAudioTrack({ microphoneId: selectedMicId }),
    AgoraRTC.createCameraVideoTrack({ cameraId: selectedCamId }),
  ]);
  localAudioTrackRef.current = audioTrack;
  localVideoTrackRef.current = videoTrack;
  await client.publish([audioTrack, videoTrack]);
}
  • 시청자는 join 만 하고 publish 를 호출하지 않습니다. 이후 user-published 로 호스트(및 코호스트) 스트림을 구독하게 됩니다.

3. 원격 사용자 구독 (호스트·시청자 공통)

호스트가 퍼블리시하면 시청자 쪽에서, 다른 호스트(코호스트)가 퍼블리시하면 호스트 쪽에서 user-published 가 발생합니다. 구독 후 메인/썸네일 영역에 track.play() 로 재생하면 됩니다.

client.on("user-published", async (user, mediaType) => {
  await client.subscribe(user, mediaType);
  if (mediaType === "video" && user.videoTrack) {
    user.videoTrack.play(videoElement, { fit: "cover" });
  }
  if (mediaType === "audio" && user.audioTrack) {
    user.audioTrack.play();
  }
});
  • 호스트 입장 시: 자신의 로컬 영상 + 코호스트 원격 영상을 썸네일/메인으로 전환할 수 있게 구성할 수 있습니다.
  • 시청자 입장 시: 첫 호스트(또는 선택한 호스트) 영상을 메인에 띄우고, 여러 호스트가 있으면 썸네일로 전환할 수 있게 할 수 있습니다.

4. 원격 오디오 볼륨 제어 (로컬에서만 소리 끄기)

라이브 스트리밍에서는 시청자가 호스트 소리를 끄기, 호스트가 코호스트 소리를 끄기 같은 수요가 있습니다. 이때는 수신 측에서 remoteAudioTrack.setVolume(0) 을 사용합니다. 스트림 자체를 끄는 것이 아니라, 내 기기에서만 그 유저 소리를 안 들으면 됩니다.

// 시청자: "호스트 소리 끔" 토글
remoteUsers.forEach((u) => {
  u.audioTrack?.setVolume?.(audienceAudioMuted ? 0 : 100);
});

// 호스트: "코호스트 소리 끔" 토글
remoteUsers.forEach((u) => {
  u.audioTrack?.setVolume?.(hostAudioMuted ? 0 : 100);
});
  • setVolume(0) / setVolume(100) 은 해당 원격 트랙을 재생 중인 로컬 인스턴스에만 적용됩니다. Agora Web SDK는 0~100 스케일을 사용합니다. 다른 시청자나 발신자 스트림에는 영향을 주지 않습니다.

5. 화면 공유 (호스트)

호스트가 화면 공유를 할 때는 RTC 통화와 동일하게, 카메라 비디오 트랙을 언퍼블리시한 뒤 화면 공유 트랙을 퍼블리시합니다. 누가 화면 공유 중인지 알리려면 RTM으로 type: "screen" 메시지를 보냅니다.

// 화면 공유 시작
const camTrack = localVideoTrackRef.current;
if (camTrack) {
  camTrack.stop?.();
  await client.unpublish([camTrack]);
}
const screenTrack = await AgoraRTC.createScreenVideoTrack(
  { optimizationMode: "detail" },
  "disable"
);
const track = Array.isArray(screenTrack) ? screenTrack[0] : screenTrack;
await client.publish([track]);
rtmClientRef.current?.publish(
  channelName,
  JSON.stringify({ type: "screen", start: true, uid: localUid })
);
  • 수신 측에서는 message 이벤트에서 type === "screen" 인 경우 screenShareUid 를 갱신해 UI에 "화면 공유 중" 표시를 할 수 있습니다.

6. 채팅 및 시그널링 (RTM)

라이브 방송에서도 채팅은 RTM으로 구현합니다. 같은 채널명으로 RTM 로그인·구독 후 publish / message 로 주고받으면 됩니다. 추가로 다음 같은 시그널링을 JSON으로 보낼 수 있습니다.

타입용도
일반 텍스트채팅 메시지
type: "screen"화면 공유 시작/중지 알림
type: "presence"참가자 수 (호스트 N명, 시청자 M명)
type: "signaling"시청자 손들기·질문 요청 등

Presence(참가자 수)
입장 시와 주기적으로(예: 15초마다) { type: "presence", uid, role } 를 보내고, 수신 측에서 presenceMap 을 유지해 "호스트 2명, 시청자 50명"처럼 표시할 수 있습니다. 오래된 항목은 타임스탬프로 정리하면 됩니다.

시청자 시그널(손들기/질문)
시청자가 버튼을 누르면 { type: "signaling", action: "raise_hand" | "question", fromUid } 를 보냅니다. 호스트 쪽에서만 이 메시지를 수신해 "시청자 시그널" 목록에 넣고, 호출 시 발언 권한을 주는 식으로 확장할 수 있습니다.

// 시청자: 손들기/질문 보내기
rtmClientRef.current?.publish(
  channelName,
  JSON.stringify({ type: "signaling", action: "raise_hand", fromUid: String(localUid) })
);

// 호스트: message 이벤트에서 type === "signaling" 이면 signals 목록에 추가

7. 공유 링크

같은 채널에 시청자를 모으려면 공유 링크를 만들 수 있습니다. URL에 쿼리로 채널명을 넣고, 시청자가 링크로 들어왔을 때 채널명을 복원해 입장하면 됩니다.

const shareLink = `${window.location.origin}${window.location.pathname}?c=${encodeURIComponent(channelName)}`;

// 입장 전: URL에서 채널명 복원
const params = new URLSearchParams(window.location.search);
const c = params.get("c");
if (c) setChannelName(c);
  • 링크를 복사해 SNS·채팅으로 공유하면, 시청자가 "시청자" 역할로 같은 방에 들어갈 수 있게 할 수 있습니다.

8. 퇴장 및 정리

퇴장 시에는 RTC leave, 로컬 트랙 close, 화면 공유 트랙 close, RTM logout 을 호출합니다. Presence용 인터벌이 있다면 clearInterval 로 정리합니다.

await client.leave();
localAudioTrackRef.current?.close?.();
localVideoTrackRef.current?.close?.();
localScreenTrackRef.current?.close?.();
clearInterval(presenceIntervalRef.current);
await rtmClientRef.current?.logout?.();

기능별 API 매핑 요약

기능사용 API
채널 입장 (호스트/시청자)createClient({ mode: "live" }), setClientRole, join
호스트 방송createMicrophoneAudioTrack, createCameraVideoTrack, publish
영상/소리 수신user-publishedsubscribe, track.play
호스트 마이크/카메라 끄기localAudioTrack.setMuted, localVideoTrack.setMuted
시청자: 호스트 소리만 끄기remoteAudioTrack.setVolume(0) (시청자 측)
호스트: 코호스트 소리만 끄기remoteAudioTrack.setVolume(0) (호스트 측)
화면 공유createScreenVideoTrack, unpublish(카메라) → publish(화면), RTM type: "screen"
채팅RTM publish / message
손들기/질문RTM type: "signaling"
참가자 수RTM type: "presence" + 주기적 발송
퇴장client.leave, 트랙 close, RTM logout

참고

자세한 API 스펙은 Agora 공식 문서 - Web SDK를 참고하세요.

© 2026 Frank Kim. All rights reserved.