IVS Web Broadcast SDK를 사용하여 게시 및 구독
이 섹션에서는 웹 앱을 사용하여 스테이지에 게시하고 구독하는 데 관련된 단계를 안내합니다.
HTML 표준 문안 생성
먼저 HTML 표준 문안을 생성하고 라이브러리를 스크립트 태그로 가져오겠습니다.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <!-- Import the SDK --> <script src="https://web-broadcast.live-video.net/1.17.0/amazon-ivs-web-broadcast.js"></script> </head> <body> <!-- TODO - fill in with next sections --> <script src="./app.js"></script> </body> </html>
토큰 입력 수락 및 Join/Leave 버튼 추가
여기서는 입력 통제로 본문을 채웁니다. 입력 통제는 토큰을 입력으로 사용하고 Join 및 Leave 버튼을 설정합니다. 일반적으로 애플리케이션은 애플리케이션의 API에서 토큰을 요청하지만 이 예제에서는 토큰을 복사하여 토큰 입력에 붙여넣습니다.
<h1>IVS Real-Time Streaming</h1> <hr /> <label for="token">Token</label> <input type="text" id="token" name="token" /> <button class="button" id="join-button">Join</button> <button class="button" id="leave-button" style="display: none;">Leave</button> <hr />
미디어 컨테이너 요소 추가
이러한 요소에는 로컬 및 원격 참가자를 위한 미디어가 포함됩니다. app.js
에 정의된 애플리케이션 로직을 로드하는 스크립트 태그를 추가합니다.
<!-- Local Participant --> <div id="local-media"></div> <!-- Remote Participants --> <div id="remote-media"></div> <!-- Load Script --> <script src="./app.js"></script>
이렇게 하면 HTML 페이지가 완성되고 브라우저에서 index.html
을 로드할 때 다음이 표시됩니다.
app.js 생성
이제 app.js
파일의 내용을 정의하도록 하겠습니다. 먼저 SDK의 글로벌에서 필요한 모든 속성을 가져옵니다.
const { Stage, LocalStageStream, SubscribeType, StageEvents, ConnectionState, StreamType } = IVSBroadcastClient;
애플리케이션 변수 생성
Join 및 Leave 버튼 HTML 요소에 대한 참조를 포함하고 애플리케이션의 상태를 저장하는 변수를 설정합니다.
let joinButton = document.getElementById("join-button"); let leaveButton = document.getElementById("leave-button"); // Stage management let stage; let joining = false; let connected = false; let localCamera; let localMic; let cameraStageStream; let micStageStream;
joinStage 1 생성: 함수 정의 및 입력 검증
joinStage
함수는 입력 토큰을 가져와서 스테이지에 대한 연결을 생성하고 getUserMedia
에서 검색된 비디오와 오디오를 게시하기 시작합니다.
먼저 함수를 정의하고 상태 및 토큰 입력을 검증합니다. 다음 몇몇 섹션에서 이 함수를 구체화하겠습니다.
const joinStage = async () => { if (connected || joining) { return; } joining = true; const token = document.getElementById("token").value; if (!token) { window.alert("Please enter a participant token"); joining = false; return; } // Fill in with the next sections };
joinStage 2 생성: 게시할 미디어 가져오기
다음은 스테이지에 게시될 미디어입니다.
async function getCamera() { // Use Max Width and Height return navigator.mediaDevices.getUserMedia({ video: true, audio: false }); } async function getMic() { return navigator.mediaDevices.getUserMedia({ video: false, audio: true }); } // Retrieve the User Media currently set on the page localCamera = await getCamera(); localMic = await getMic(); // Create StageStreams for Audio and Video cameraStageStream = new LocalStageStream(localCamera.getVideoTracks()[0]); micStageStream = new LocalStageStream(localMic.getAudioTracks()[0]);
joinStage 3 생성: 스테이지 전략 정의 및 스테이지 생성
이 단계 전략은 SDK가 게시할 항목과 구독할 참가자를 결정하는 데 사용하는 결정 로직의 핵심입니다. 함수의 용도에 대한 자세한 내용은 전략을 참조하세요.
이 전략은 간단합니다. 스테이지에 참가한 후 방금 검색한 스트림을 게시하고 모든 원격 참가자의 오디오와 비디오를 구독합니다.
const strategy = { stageStreamsToPublish() { return [cameraStageStream, micStageStream]; }, shouldPublishParticipant() { return true; }, shouldSubscribeToParticipant() { return SubscribeType.AUDIO_VIDEO; } }; stage = new Stage(token, strategy);
joinStage 4 생성: 스테이지 이벤트 처리 및 미디어 렌더링
스테이지는 많은 이벤트를 내보냅니다. 페이지에서 미디어를 렌더링하고 제거하려면 STAGE_PARTICIPANT_STREAMS_ADDED
와 STAGE_PARTICIPANT_LEFT
를 수신해야 합니다. 이벤트에는 보다 포괄적인 이벤트 세트가 나열됩니다.
여기서는 필요한 DOM 요소를 관리하는 데 도움이 되는 4가지 도우미 함수인 setupParticipant
, teardownParticipant
, createVideoEl
및 createContainer
를 생성합니다.
stage.on(StageEvents.STAGE_CONNECTION_STATE_CHANGED, (state) => { connected = state === ConnectionState.CONNECTED; if (connected) { joining = false; joinButton.style = "display: none"; leaveButton.style = "display: inline-block"; } }); stage.on( StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED, (participant, streams) => { console.log("Participant Media Added: ", participant, streams); let streamsToDisplay = streams; if (participant.isLocal) { // Ensure to exclude local audio streams, otherwise echo will occur streamsToDisplay = streams.filter( (stream) => stream.streamType === StreamType.VIDEO ); } const videoEl = setupParticipant(participant); streamsToDisplay.forEach((stream) => videoEl.srcObject.addTrack(stream.mediaStreamTrack) ); } ); stage.on(StageEvents.STAGE_PARTICIPANT_LEFT, (participant) => { console.log("Participant Left: ", participant); teardownParticipant(participant); }); // Helper functions for managing DOM function setupParticipant({ isLocal, id }) { const groupId = isLocal ? "local-media" : "remote-media"; const groupContainer = document.getElementById(groupId); const participantContainerId = isLocal ? "local" : id; const participantContainer = createContainer(participantContainerId); const videoEl = createVideoEl(participantContainerId); participantContainer.appendChild(videoEl); groupContainer.appendChild(participantContainer); return videoEl; } function teardownParticipant({ isLocal, id }) { const groupId = isLocal ? "local-media" : "remote-media"; const groupContainer = document.getElementById(groupId); const participantContainerId = isLocal ? "local" : id; const participantDiv = document.getElementById( participantContainerId + "-container" ); if (!participantDiv) { return; } groupContainer.removeChild(participantDiv); } function createVideoEl(id) { const videoEl = document.createElement("video"); videoEl.id = id; videoEl.autoplay = true; videoEl.playsInline = true; videoEl.srcObject = new MediaStream(); return videoEl; } function createContainer(id) { const participantContainer = document.createElement("div"); participantContainer.classList = "participant-container"; participantContainer.id = id + "-container"; return participantContainer; }
joinStage 5 생성: 스테이지에 참가
드디어 스테이지에 참가하여 joinStage
함수를 완성해 보겠습니다.
try { await stage.join(); } catch (err) { joining = false; connected = false; console.error(err.message); }
leaveStage 생성
leave 버튼이 간접적으로 호출할 leaveStage
함수를 정의합니다.
const leaveStage = async () => { stage.leave(); joining = false; connected = false; };
입력 이벤트 핸들러 초기화
app.js
파일에 마지막 함수를 하나 추가하겠습니다. 이 함수는 페이지가 로드될 때 즉시 간접적으로 호출되고 스테이지 참가 및 탈퇴를 위한 이벤트 핸들러를 설정합니다.
const init = async () => { try { // Prevents issues on Safari/FF so devices are not blank await navigator.mediaDevices.getUserMedia({ video: true, audio: true }); } catch (e) { alert( "Problem retrieving media! Enable camera and microphone permissions." ); } joinButton.addEventListener("click", () => { joinStage(); }); leaveButton.addEventListener("click", () => { leaveStage(); joinButton.style = "display: inline-block"; leaveButton.style = "display: none"; }); }; init(); // call the function
애플리케이션 실행 및 토큰 제공
이 부분에서는 로컬에서 또는 다른 사용자와 웹 페이지를 공유하고, 페이지를 열고, 참가자 토큰을 입력하여 스테이지에 참가할 수 있습니다.
다음 단계
npm, React 등과 관련된 자세한 예제를 확인하려면 IVS 브로드캐스트 SDK: 웹 안내서(실시간 스트리밍 가이드)를 참조하세요.