使用 IVS Web 广播 SDK 发布和订阅
本部分将引导您完成使用 Web 应用程序发布和订阅舞台所涉及的步骤。
创建 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>
接受令牌输入并添加“加入/离开”按钮
使用输入控件在此处填充正文。它们将令牌作为输入,然后设置加入和离开按钮。通常,应用程序会从应用程序的 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;
创建应用程序变量
建立变量以保存对加入和离开按钮 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 将使用此策略来决定要发布什么内容和订阅哪些参与者。有关此函数用途的更多信息,请参阅 Strategy。
这个策略很简单。加入舞台后,发布刚刚检索的流,并订阅每个远程参与者的音频和视频:
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 元素: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
定义 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:网络指南(实时直播功能指南)。