Diff
checker
文本
文本
圖像
文檔
Excel
文件夾
Legal
Enterprise
桌面版
定價
登入
下載 Diffchecker 桌面版
比較文本
尋找兩個文字檔案之間的差異
工具
歷史
即時編輯器
摺疊未變更行
關閉換行
檢視
拆分
統一
比對精度
智能
單詞
字符
語法突出顯示
選擇語法
忽略
文字轉換
前往第一個差異
編輯輸入
Diffchecker Desktop
執行Diffchecker最安全的方式。取得Diffchecker桌面應用程式:您的差異永遠不會離開您的電腦!
取得桌面版
index.html comms-getting-started
建立於
3 年前
差異永不過期
清除
匯出
分享
解釋
49 刪除
行
總計
刪除
字符
總計
刪除
要繼續使用此功能,請升級到
Diff
checker
Pro
查看價格
287 行
全部複製
81 新增
行
總計
新增
字符
總計
新增
要繼續使用此功能,請升級到
Diff
checker
Pro
查看價格
301 行
全部複製
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="en">
<html lang="en">
<head>
<head>
<meta charset="utf-8">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>Dolby.io Getting Started with Video Calls</title>
<title>Dolby.io Getting Started with Video Calls</title>
<link rel="shortcut icon" href="https://go.dolby.io/hubfs/Dolby_April2021/images/favicon-32x32.png">
<link rel="shortcut icon" href="https://go.dolby.io/hubfs/Dolby_April2021/images/favicon-32x32.png">
<!-- Bootstrap Bundle -->
<!-- Bootstrap Bundle -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css">
<!-- Dolby.io Web SDK -->
<!-- Dolby.io Web SDK -->
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@voxeet/voxeet-web-sdk/dist/voxeet-sdk.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@voxeet/voxeet-web-sdk/dist/voxeet-sdk.js"></script>
複製
已複製
複製
已複製
<script type="text/javascript" src="
https://developer.dolby.io/demos/comms-sdk-web-getting-started
/util/dolbyio-auth-helper.js"></script>
<script type="text/javascript" src="
..
/util/dolbyio-auth-helper.js"></script>
<!-- Auth0 Single Page Application SDK -->
<script src="https://cdn.auth0.com/js/auth0-spa-js/1.2/auth0-spa-js.production.js"></script>
<script src="./app.js"></script>
</head>
</head>
<body>
<body>
<div class="container bg-dark text-white gx-4 px-4 py-4 mt-3 rounded">
<div class="container bg-dark text-white gx-4 px-4 py-4 mt-3 rounded">
複製
已複製
複製
已複製
<img src="https://go.dolby.io/hubfs/raw_assets/public/Dolby_April2021/images/dolby-io-logo.svg"
/>
<img src="https://go.dolby.io/hubfs/raw_assets/public/Dolby_April2021/images/dolby-io-logo.svg"
/>
<h1>Getting Started with
Video Calls
</h1>
<h1>Getting Started with
Auth0 User Authentication
</h1>
</div>
<div>
<style>
.hidden {
display: none;
}
label {
margin-bottom: 10px;
display: block;
}
</style>
<br>
<button id="btn-login" class="btn btn-dark" disabled="true">Log in</button>
<button id="btn-logout" class="btn btn-dark" disabled="true">Log out</button>
</div>
</div>
複製
已複製
複製
已複製
<!-- Video Call Elements Hidden Until the Users Logs in -->
<div class="hidden" id="gated-content">
<p>
You're seeing this content because you're currently
<strong>logged in</strong>.
</p>
複製
已複製
複製
已複製
<div class="container px-4 mt-4">
<div class="container px-4 mt-4">
<div class="row justify-content-around mt-3">
<div class="row justify-content-around mt-3">
<div class="col-4 shadow p-3 mb-5 bg-body rounded">
<div class="col-4 shadow p-3 mb-5 bg-body rounded">
<h2>Self-View</h2>
<h2>Self-View</h2>
<style>
<style>
#self-view video {
/* Flip the display of the local user in self view */
#self-view video {
/* Flip the display of the local user in self view */
-webkit-transform: rotateY(180deg); /* Safari, Chrome */
-webkit-transform: rotateY(180deg); /* Safari, Chrome */
-moz-transform: rotateY(180deg); /* Firefox */
-moz-transform: rotateY(180deg); /* Firefox */
transform: rotateY(180deg); /* Microsoft, etc. */
transform: rotateY(180deg); /* Microsoft, etc. */
複製
已複製
複製
已複製
}
}
</style>
</style>
<div id="self-view"> <!-- Container for the local participant media stream -->
<div id="self-view"> <!-- Container for the local participant media stream -->
<p id="self-view-username"></p>
<p id="self-view-username"></p>
<i class="display-1 bi bi-person-video position-relative"></i>
<i class="display-1 bi bi-person-video position-relative"></i>
</div>
<button type="button" class="btn btn-dark" id="btn-join">Join</button>
<button type="button" class="btn btn-dark" id="btn-leave">Leave</button>
</div>
</div>
複製
已複製
複製
已複製
<button type="button" class="btn btn-dark" id="btn-join">Join</button>
<div class="col-4 shadow p-3 mb-5 bg-body rounded">
<button type="button" class="btn btn-dark" id="btn-leave">Leave</button>
<h2>Remote-View</h2>
</div>
<div id="remote-view"> <!-- Container for the remote participant media stream -->
<p id="remote-view-username"></p>
<div class="col-4 shadow p-3 mb-5 bg-body rounded">
<i class="display-1 bi bi-person-video position-relative"></i>
<h2>Remote-View</h2>
</div>
<div id="remote-view"> <!-- Container for the remote participant media stream -->
<p id="remote-view-username"></p>
<button type="button" class="btn btn-dark" id="btn-invite"><i class="bi bi-clipboard2-plus-fill"></i> Invite</button>
<i class="display-1 bi bi-person-video position-relative"></i>
</div>
</div>
複製
已複製
複製
已複製
<button type="button" class="btn btn-dark" id="btn-invite"><i class="bi bi-clipboard2-plus-fill"></i> Invite</button>
</div>
</div>
</div>
</div>
複製
已複製
複製
已複製
</div>
<div class="container px-4 py-4 mt-3">
<p id="message"></p>
<p><a href="https://docs.dolby.io/communications-apis/docs/getting-started-with-the-javascript-sdk">Explore More Tutorials</a></p>
</div>
複製
已複製
複製
已複製
<!-- Prompt user for token and alias if not provided in URL -->
<div class="container px-4 py-4 mt-3">
<div class="modal fade" id="token-prompt" tabindex="-1" aria-labelledby="token-prompt-label" aria-hidden="true">
<
p
id="
message
"></
p
>
<div class="modal-dialog">
<p><a href="https://docs.dolby.io/communications-apis/docs/getting-started-with-the-javascript-sdk">Explore More Tutorials</a></p>
<div class="modal-content">
<div class="modal-header">
<
h5 class="modal-title"
id="
token-prompt-label">Dolby.io Dashboard</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close
"></
button
>
</div>
<div class="modal-body">
<label for="input-token" class="form-label">Demo Client Access Token:</label>
<input id="input-token" type="text" class="form-control">
</div>
<div class="modal-footer">
<button type="button" id="btn-token" class="btn btn-primary">Authenticate</button>
</div>
</div>
</div>
</div>
</div>
</div>
複製
已複製
複製
已複製
<!-- Bootstrap Bundle -->
<!-- Bootstrap Bundle -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<!-- Dolby.io Starter Application -->
<!-- Dolby.io Starter Application -->
<script type="text/javascript">
<script type="text/javascript">
const shareMessage = (message) => {
const shareMessage = (message) => {
document.getElementById("message").innerText = message;
document.getElementById("message").innerText = message;
}
}
/**
/**
* Start by initializing the Web SDK with an access token. This starter project
* Start by initializing the Web SDK with an access token. This starter project
複製
已複製
複製
已複製
* utilizes a helper function to
pull
the token
from the query parameters in the URL
.
* utilizes a helper function to
provide
the token
with an API call
.
*/
*/
複製
已複製
複製
已複製
const initializeToken =
() => {
const initializeToken =
async
() => {
console.group("Step 1: Initialize the SDK");
console.group("Step 1: Initialize the SDK");
複製
已複製
複製
已複製
const token =
dolbyio.getAccessToken();
const token =
await
dolbyio.getAccessToken();
VoxeetSDK.initializeToken(token, () => { console.log("Get a New Access Token"); });
VoxeetSDK.initializeToken(token, () => { console.log("Get a New Access Token"); });
shareMessage("Step 1: Web SDK initialized.");
shareMessage("Step 1: Web SDK initialized.");
console.groupEnd();
console.groupEnd();
return token;
return token;
}
}
/**
/**
* Start a session by establishing a communication link between this client application
* Start a session by establishing a communication link between this client application
* and the Dolby.io Platform. You need to provide the client name when establishing
* and the Dolby.io Platform. You need to provide the client name when establishing
* a new session, often this is the name that will be used by the participant.
* a new session, often this is the name that will be used by the participant.
*/
*/
const openSession = async (sessionName) => {
const openSession = async (sessionName) => {
console.group("Step 2: Open a Session");
console.group("Step 2: Open a Session");
console.log(`Session Name: ${sessionName}`);
console.log(`Session Name: ${sessionName}`);
try {
try {
await VoxeetSDK.session.open({ name: sessionName });
await VoxeetSDK.session.open({ name: sessionName });
shareMessage("Step 2: Session opened.");
shareMessage("Step 2: Session opened.");
} catch (error) {
} catch (error) {
console.error(error);
console.error(error);
shareMessage(`Error opening session: ${error}`);
shareMessage(`Error opening session: ${error}`);
}
}
console.groupEnd();
console.groupEnd();
}
}
/**
/**
* Bi-directional communications for multiple participants occurs in a conference. Initially,
* Bi-directional communications for multiple participants occurs in a conference. Initially,
* the conference must be created before it can be joined. The conference should be given a
* the conference must be created before it can be joined. The conference should be given a
* unique and meaningful alias to help identify it among multiple conferences in an account.
* unique and meaningful alias to help identify it among multiple conferences in an account.
*
*
* This should be in response to a user event so that they may approve media access to the
* This should be in response to a user event so that they may approve media access to the
* microphone and camera.
* microphone and camera.
*/
*/
const createAndJoinConference = async (conferenceAlias, participantName) => {
const createAndJoinConference = async (conferenceAlias, participantName) => {
if (!VoxeetSDK.session.isOpen()) { await openSession(participantName); };
if (!VoxeetSDK.session.isOpen()) { await openSession(participantName); };
console.group("Step 3: Create and Join a Conference");
console.group("Step 3: Create and Join a Conference");
console.log(`Conference Alias: ${conferenceAlias}`);
console.log(`Conference Alias: ${conferenceAlias}`);
const joinOptions = {
const joinOptions = {
constraints: { audio: true, video: true }
constraints: { audio: true, video: true }
};
};
const conferenceOptions = {
const conferenceOptions = {
alias: conferenceAlias
alias: conferenceAlias
}
}
try {
try {
const conference = await VoxeetSDK.conference.create(conferenceOptions);
const conference = await VoxeetSDK.conference.create(conferenceOptions);
await VoxeetSDK.conference.join(conference, joinOptions);
await VoxeetSDK.conference.join(conference, joinOptions);
shareMessage(`Step 3: Conference '${conferenceAlias}' created and joined.`)
shareMessage(`Step 3: Conference '${conferenceAlias}' created and joined.`)
} catch (error) {
} catch (error) {
console.error(error);
console.error(error);
}
}
console.groupEnd();
console.groupEnd();
};
};
/**
/**
* The SDK will trigger server-generated events which we can respond to
* The SDK will trigger server-generated events which we can respond to
* for intended functionality.
* for intended functionality.
*/
*/
const handleConferenceFlow = () => {
const handleConferenceFlow = () => {
// Custom behavior for when there is a media stream added
// Custom behavior for when there is a media stream added
VoxeetSDK.conference.on("streamAdded", (participant, stream) => {
VoxeetSDK.conference.on("streamAdded", (participant, stream) => {
console.log(`Stream Added for ${participant.info.name}`);
console.log(`Stream Added for ${participant.info.name}`);
console.log(` Type: ${stream.type}`);
console.log(` Type: ${stream.type}`);
console.log(` Video Tracks: ${stream.getVideoTracks().length}`);
console.log(` Video Tracks: ${stream.getVideoTracks().length}`);
if (stream.type === "Camera") {
if (stream.type === "Camera") {
shareVideo(participant, stream);
shareVideo(participant, stream);
}
}
});
});
// Custom behavior for when there is a media stream updated which happens once an attendee starts sharing video
// Custom behavior for when there is a media stream updated which happens once an attendee starts sharing video
VoxeetSDK.conference.on("streamUpdated", (participant, stream) => {
VoxeetSDK.conference.on("streamUpdated", (participant, stream) => {
console.log(`Stream Updated for ${participant.info.name}`);
console.log(`Stream Updated for ${participant.info.name}`);
console.log(` Type: ${stream.type}`);
console.log(` Type: ${stream.type}`);
console.log(` Video Tracks: ${stream.getVideoTracks().length}`);
console.log(` Video Tracks: ${stream.getVideoTracks().length}`);
if (stream.type === "Camera" && stream.getVideoTracks().length) {
if (stream.type === "Camera" && stream.getVideoTracks().length) {
shareVideo(participant, stream);
shareVideo(participant, stream);
}
}
});
});
// Custom behavior for when the app stops receiving a media stream for remote participants
// Custom behavior for when the app stops receiving a media stream for remote participants
VoxeetSDK.conference.on("streamRemoved", (participant, stream) => {
VoxeetSDK.conference.on("streamRemoved", (participant, stream) => {
console.log(`Stream Removed for ${participant.info.name}`);
console.log(`Stream Removed for ${participant.info.name}`);
const videoNode = document.getElementById(`video-${participant.id}`);
const videoNode = document.getElementById(`video-${participant.id}`);
if (videoNode) {
if (videoNode) {
videoNode.parentNode.removeChild(videoNode);
videoNode.parentNode.removeChild(videoNode);
}
}
});
});
// Custom behavior for when the participant has left the conference
// Custom behavior for when the participant has left the conference
VoxeetSDK.conference.on("left", async () => {
VoxeetSDK.conference.on("left", async () => {
await VoxeetSDK.session.close();
await VoxeetSDK.session.close();
console.log("Session closed.");
console.log("Session closed.");
});
});
}
}
/**
/**
* When a new participant camera media stream is detected, we determine which
* When a new participant camera media stream is detected, we determine which
* part of the user interface to update and create a video element that will
* part of the user interface to update and create a video element that will
* display the incoming stream.
* display the incoming stream.
*/
*/
const shareVideo = (participant, stream) => {
const shareVideo = (participant, stream) => {
console.group("Step 4: Start and Share Video");
console.group("Step 4: Start and Share Video");
let perspective = "self-view";
let perspective = "self-view";
if (VoxeetSDK.session.participant.id !== participant.id) {
if (VoxeetSDK.session.participant.id !== participant.id) {
console.log("Adding media stream for remote user.");
console.log("Adding media stream for remote user.");
perspective = "remote-view";
perspective = "remote-view";
}
}
let videoNode = document.getElementById(`video-${participant.id}`);
let videoNode = document.getElementById(`video-${participant.id}`);
if (videoNode) {
if (videoNode) {
console.log("Video node already created");
console.log("Video node already created");
} else {
} else {
console.log(`Creating a video node: video-${participant.id}`);
console.log(`Creating a video node: video-${participant.id}`);
videoNode = document.createElement("video");
videoNode = document.createElement("video");
videoNode.setAttribute("id", `video-${participant.id}`);
videoNode.setAttribute("id", `video-${participant.id}`);
videoNode.setAttribute("height", "100%");
videoNode.setAttribute("height", "100%");
videoNode.setAttribute("width", "100%");
videoNode.setAttribute("width", "100%");
videoNode.muted = true; // Don't echo local audio
videoNode.muted = true; // Don't echo local audio
videoNode.autoplay = true; // Start right away
videoNode.autoplay = true; // Start right away
videoNode.playsinline = true; // Not full screen
videoNode.playsinline = true; // Not full screen
const videoContainer = document.getElementById(perspective);
const videoContainer = document.getElementById(perspective);
videoContainer.lastElementChild.replaceWith(videoNode);
videoContainer.lastElementChild.replaceWith(videoNode);
videoContainer.firstElementChild.innerText = participant.info.name;
videoContainer.firstElementChild.innerText = participant.info.name;
}
}
navigator.attachMediaStream(videoNode, stream);
navigator.attachMediaStream(videoNode, stream);
shareMessage(`Step 4: Video of participant '${participant.info.name}' started.`);
shareMessage(`Step 4: Video of participant '${participant.info.name}' started.`);
console.groupEnd();
console.groupEnd();
}
}
/**
/**
* When the user decides to leave the conference you should stop sending the audio/video
* When the user decides to leave the conference you should stop sending the audio/video
* stream.
* stream.
*/
*/
const leaveConference = async () => {
const leaveConference = async () => {
console.group("Final Step: Leave the Conference");
console.group("Final Step: Leave the Conference");
try {
try {
await VoxeetSDK.conference.leave();
await VoxeetSDK.conference.leave();
shareMessage("Getting Started Success: Conference has ended.")
shareMessage("Getting Started Success: Conference has ended.")
} catch (error) {
} catch (error) {
console.error(error);
console.error(error);
}
}
console.groupEnd();
console.groupEnd();
}
}
const main = async () => {
const main = async () => {
複製
已複製
複製
已複製
// Configure the
application
from query parameter values
// When the web page has finished loading, configure Auth0 client, check the user's login state, and update the UI accordingly.
window.onload = async () => {
await configureClient();
await processLoginState();
// Function below will use initializeToken and openSession functions as callbacks in it after authentication.
await updateUI(initializeToken, openSession);
};
// When user clicks the Log in button, redirect user to Auth0 to access the conference only after authentication
document.getElementById("btn-login").onclick = async () => {
await login();
};
// When user clicks the Log out button, log out and clean Auht0 browser cookies
document.getElementById("btn-logout").onclick = async () => {
await logout();
};
// Configure the
conference alias
from query parameter values
const queryParams = new URLSearchParams(window.location.search);
const queryParams = new URLSearchParams(window.location.search);
複製
已複製
複製
已複製
const name = queryParams.get("name") || "developer";
const alias = queryParams.get("alias") || "web-sdk-starter";
const alias = queryParams.get("alias") || "web-sdk-starter";
複製
已複製
複製
已複製
// Establish Real-time Communications by first initializing the Dolby.io Web SDK with credentials
const token = await initializeToken();
// Start a new session and connect to the Dolby.io platform establishing a client-server link
await openSession(name);
// When user clicks the Join button, start and join a conference for the given alias
// When user clicks the Join button, start and join a conference for the given alias
document.getElementById("btn-join").onclick = async () => {
document.getElementById("btn-join").onclick = async () => {
複製
已複製
複製
已複製
await createAndJoinConference(alias
, name
);
await createAndJoinConference(alias
);
};
};
// Define custom behavior for activity that occurs during a video call
// Define custom behavior for activity that occurs during a video call
handleConferenceFlow();
handleConferenceFlow();
// When user clicks the Invite button, generate a url to join the same conference
// When user clicks the Invite button, generate a url to join the same conference
document.getElementById("btn-invite").onclick = () => {
document.getElementById("btn-invite").onclick = () => {
console.group("Step 5: Invite a remote participant")
console.group("Step 5: Invite a remote participant")
複製
已複製
複製
已複製
let url = `http
s
://
developer.dolby.io/demos/comms-sdk-web-getting-started/index.html?token=${token}&
alias=${alias}
&name=guest
`;
let url = `http
://
localhost:3000/?
alias=${alias}
`;
console.log(`Invite a guest with URL: ${url}`);
console.log(`Invite a guest with URL: ${url}`);
shareMessage(`Share the URL copied to your browser clipboard: ${url}`);
shareMessage(`Share the URL copied to your browser clipboard: ${url}`);
navigator.clipboard.writeText(url);
navigator.clipboard.writeText(url);
console.groupEnd();
console.groupEnd();
}
}
// When user clicks the Leave button, end the conference
// When user clicks the Leave button, end the conference
document.getElementById("btn-leave").onclick = async () => {
document.getElementById("btn-leave").onclick = async () => {
await leaveConference();
await leaveConference();
console.log("Getting Started Guide complete, congratulations!");
console.log("Getting Started Guide complete, congratulations!");
};
};
};
};
main();
main();
</script>
</script>
</body>
</body>
</html>
</html>
已保存差異
原始文本
開啟檔案
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no"> <title>Dolby.io Getting Started with Video Calls</title> <link rel="shortcut icon" href="https://go.dolby.io/hubfs/Dolby_April2021/images/favicon-32x32.png"> <!-- Bootstrap Bundle --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css"> <!-- Dolby.io Web SDK --> <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@voxeet/voxeet-web-sdk/dist/voxeet-sdk.js"></script> <script type="text/javascript" src="https://developer.dolby.io/demos/comms-sdk-web-getting-started/util/dolbyio-auth-helper.js"></script> </head> <body> <div class="container bg-dark text-white gx-4 px-4 py-4 mt-3 rounded"> <img src="https://go.dolby.io/hubfs/raw_assets/public/Dolby_April2021/images/dolby-io-logo.svg"/> <h1>Getting Started with Video Calls</h1> </div> <div class="container px-4 mt-4"> <div class="row justify-content-around mt-3"> <div class="col-4 shadow p-3 mb-5 bg-body rounded"> <h2>Self-View</h2> <style> #self-view video { /* Flip the display of the local user in self view */ -webkit-transform: rotateY(180deg); /* Safari, Chrome */ -moz-transform: rotateY(180deg); /* Firefox */ transform: rotateY(180deg); /* Microsoft, etc. */ } </style> <div id="self-view"> <!-- Container for the local participant media stream --> <p id="self-view-username"></p> <i class="display-1 bi bi-person-video position-relative"></i> </div> <button type="button" class="btn btn-dark" id="btn-join">Join</button> <button type="button" class="btn btn-dark" id="btn-leave">Leave</button> </div> <div class="col-4 shadow p-3 mb-5 bg-body rounded"> <h2>Remote-View</h2> <div id="remote-view"> <!-- Container for the remote participant media stream --> <p id="remote-view-username"></p> <i class="display-1 bi bi-person-video position-relative"></i> </div> <button type="button" class="btn btn-dark" id="btn-invite"><i class="bi bi-clipboard2-plus-fill"></i> Invite</button> </div> </div> </div> <div class="container px-4 py-4 mt-3"> <p id="message"></p> <p><a href="https://docs.dolby.io/communications-apis/docs/getting-started-with-the-javascript-sdk">Explore More Tutorials</a></p> </div> <!-- Prompt user for token and alias if not provided in URL --> <div class="modal fade" id="token-prompt" tabindex="-1" aria-labelledby="token-prompt-label" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="token-prompt-label">Dolby.io Dashboard</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <label for="input-token" class="form-label">Demo Client Access Token:</label> <input id="input-token" type="text" class="form-control"> </div> <div class="modal-footer"> <button type="button" id="btn-token" class="btn btn-primary">Authenticate</button> </div> </div> </div> </div> <!-- Bootstrap Bundle --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script> <!-- Dolby.io Starter Application --> <script type="text/javascript"> const shareMessage = (message) => { document.getElementById("message").innerText = message; } /** * Start by initializing the Web SDK with an access token. This starter project * utilizes a helper function to pull the token from the query parameters in the URL. */ const initializeToken = () => { console.group("Step 1: Initialize the SDK"); const token = dolbyio.getAccessToken(); VoxeetSDK.initializeToken(token, () => { console.log("Get a New Access Token"); }); shareMessage("Step 1: Web SDK initialized."); console.groupEnd(); return token; } /** * Start a session by establishing a communication link between this client application * and the Dolby.io Platform. You need to provide the client name when establishing * a new session, often this is the name that will be used by the participant. */ const openSession = async (sessionName) => { console.group("Step 2: Open a Session"); console.log(`Session Name: ${sessionName}`); try { await VoxeetSDK.session.open({ name: sessionName }); shareMessage("Step 2: Session opened."); } catch (error) { console.error(error); shareMessage(`Error opening session: ${error}`); } console.groupEnd(); } /** * Bi-directional communications for multiple participants occurs in a conference. Initially, * the conference must be created before it can be joined. The conference should be given a * unique and meaningful alias to help identify it among multiple conferences in an account. * * This should be in response to a user event so that they may approve media access to the * microphone and camera. */ const createAndJoinConference = async (conferenceAlias, participantName) => { if (!VoxeetSDK.session.isOpen()) { await openSession(participantName); }; console.group("Step 3: Create and Join a Conference"); console.log(`Conference Alias: ${conferenceAlias}`); const joinOptions = { constraints: { audio: true, video: true } }; const conferenceOptions = { alias: conferenceAlias } try { const conference = await VoxeetSDK.conference.create(conferenceOptions); await VoxeetSDK.conference.join(conference, joinOptions); shareMessage(`Step 3: Conference '${conferenceAlias}' created and joined.`) } catch (error) { console.error(error); } console.groupEnd(); }; /** * The SDK will trigger server-generated events which we can respond to * for intended functionality. */ const handleConferenceFlow = () => { // Custom behavior for when there is a media stream added VoxeetSDK.conference.on("streamAdded", (participant, stream) => { console.log(`Stream Added for ${participant.info.name}`); console.log(` Type: ${stream.type}`); console.log(` Video Tracks: ${stream.getVideoTracks().length}`); if (stream.type === "Camera") { shareVideo(participant, stream); } }); // Custom behavior for when there is a media stream updated which happens once an attendee starts sharing video VoxeetSDK.conference.on("streamUpdated", (participant, stream) => { console.log(`Stream Updated for ${participant.info.name}`); console.log(` Type: ${stream.type}`); console.log(` Video Tracks: ${stream.getVideoTracks().length}`); if (stream.type === "Camera" && stream.getVideoTracks().length) { shareVideo(participant, stream); } }); // Custom behavior for when the app stops receiving a media stream for remote participants VoxeetSDK.conference.on("streamRemoved", (participant, stream) => { console.log(`Stream Removed for ${participant.info.name}`); const videoNode = document.getElementById(`video-${participant.id}`); if (videoNode) { videoNode.parentNode.removeChild(videoNode); } }); // Custom behavior for when the participant has left the conference VoxeetSDK.conference.on("left", async () => { await VoxeetSDK.session.close(); console.log("Session closed."); }); } /** * When a new participant camera media stream is detected, we determine which * part of the user interface to update and create a video element that will * display the incoming stream. */ const shareVideo = (participant, stream) => { console.group("Step 4: Start and Share Video"); let perspective = "self-view"; if (VoxeetSDK.session.participant.id !== participant.id) { console.log("Adding media stream for remote user."); perspective = "remote-view"; } let videoNode = document.getElementById(`video-${participant.id}`); if (videoNode) { console.log("Video node already created"); } else { console.log(`Creating a video node: video-${participant.id}`); videoNode = document.createElement("video"); videoNode.setAttribute("id", `video-${participant.id}`); videoNode.setAttribute("height", "100%"); videoNode.setAttribute("width", "100%"); videoNode.muted = true; // Don't echo local audio videoNode.autoplay = true; // Start right away videoNode.playsinline = true; // Not full screen const videoContainer = document.getElementById(perspective); videoContainer.lastElementChild.replaceWith(videoNode); videoContainer.firstElementChild.innerText = participant.info.name; } navigator.attachMediaStream(videoNode, stream); shareMessage(`Step 4: Video of participant '${participant.info.name}' started.`); console.groupEnd(); } /** * When the user decides to leave the conference you should stop sending the audio/video * stream. */ const leaveConference = async () => { console.group("Final Step: Leave the Conference"); try { await VoxeetSDK.conference.leave(); shareMessage("Getting Started Success: Conference has ended.") } catch (error) { console.error(error); } console.groupEnd(); } const main = async () => { // Configure the application from query parameter values const queryParams = new URLSearchParams(window.location.search); const name = queryParams.get("name") || "developer"; const alias = queryParams.get("alias") || "web-sdk-starter"; // Establish Real-time Communications by first initializing the Dolby.io Web SDK with credentials const token = await initializeToken(); // Start a new session and connect to the Dolby.io platform establishing a client-server link await openSession(name); // When user clicks the Join button, start and join a conference for the given alias document.getElementById("btn-join").onclick = async () => { await createAndJoinConference(alias, name); }; // Define custom behavior for activity that occurs during a video call handleConferenceFlow(); // When user clicks the Invite button, generate a url to join the same conference document.getElementById("btn-invite").onclick = () => { console.group("Step 5: Invite a remote participant") let url = `https://developer.dolby.io/demos/comms-sdk-web-getting-started/index.html?token=${token}&alias=${alias}&name=guest`; console.log(`Invite a guest with URL: ${url}`); shareMessage(`Share the URL copied to your browser clipboard: ${url}`); navigator.clipboard.writeText(url); console.groupEnd(); } // When user clicks the Leave button, end the conference document.getElementById("btn-leave").onclick = async () => { await leaveConference(); console.log("Getting Started Guide complete, congratulations!"); }; }; main(); </script> </body> </html>
更改後文本
開啟檔案
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no"> <title>Dolby.io Getting Started with Video Calls</title> <link rel="shortcut icon" href="https://go.dolby.io/hubfs/Dolby_April2021/images/favicon-32x32.png"> <!-- Bootstrap Bundle --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css"> <!-- Dolby.io Web SDK --> <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@voxeet/voxeet-web-sdk/dist/voxeet-sdk.js"></script> <script type="text/javascript" src="../util/dolbyio-auth-helper.js"></script> <!-- Auth0 Single Page Application SDK --> <script src="https://cdn.auth0.com/js/auth0-spa-js/1.2/auth0-spa-js.production.js"></script> <script src="./app.js"></script> </head> <body> <div class="container bg-dark text-white gx-4 px-4 py-4 mt-3 rounded"> <img src="https://go.dolby.io/hubfs/raw_assets/public/Dolby_April2021/images/dolby-io-logo.svg" /> <h1>Getting Started with Auth0 User Authentication </h1> </div> <div> <style> .hidden { display: none; } label { margin-bottom: 10px; display: block; } </style> <br> <button id="btn-login" class="btn btn-dark" disabled="true">Log in</button> <button id="btn-logout" class="btn btn-dark" disabled="true">Log out</button> </div> <!-- Video Call Elements Hidden Until the Users Logs in --> <div class="hidden" id="gated-content"> <p> You're seeing this content because you're currently <strong>logged in</strong>. </p> <div class="container px-4 mt-4"> <div class="row justify-content-around mt-3"> <div class="col-4 shadow p-3 mb-5 bg-body rounded"> <h2>Self-View</h2> <style> #self-view video { /* Flip the display of the local user in self view */ -webkit-transform: rotateY(180deg); /* Safari, Chrome */ -moz-transform: rotateY(180deg); /* Firefox */ transform: rotateY(180deg); /* Microsoft, etc. */ } </style> <div id="self-view"> <!-- Container for the local participant media stream --> <p id="self-view-username"></p> <i class="display-1 bi bi-person-video position-relative"></i> </div> <button type="button" class="btn btn-dark" id="btn-join">Join</button> <button type="button" class="btn btn-dark" id="btn-leave">Leave</button> </div> <div class="col-4 shadow p-3 mb-5 bg-body rounded"> <h2>Remote-View</h2> <div id="remote-view"> <!-- Container for the remote participant media stream --> <p id="remote-view-username"></p> <i class="display-1 bi bi-person-video position-relative"></i> </div> <button type="button" class="btn btn-dark" id="btn-invite"><i class="bi bi-clipboard2-plus-fill"></i> Invite</button> </div> </div> </div> <div class="container px-4 py-4 mt-3"> <p id="message"></p> <p><a href="https://docs.dolby.io/communications-apis/docs/getting-started-with-the-javascript-sdk">Explore More Tutorials</a></p> </div> </div> <!-- Bootstrap Bundle --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script> <!-- Dolby.io Starter Application --> <script type="text/javascript"> const shareMessage = (message) => { document.getElementById("message").innerText = message; } /** * Start by initializing the Web SDK with an access token. This starter project * utilizes a helper function to provide the token with an API call. */ const initializeToken = async () => { console.group("Step 1: Initialize the SDK"); const token = await dolbyio.getAccessToken(); VoxeetSDK.initializeToken(token, () => { console.log("Get a New Access Token"); }); shareMessage("Step 1: Web SDK initialized."); console.groupEnd(); return token; } /** * Start a session by establishing a communication link between this client application * and the Dolby.io Platform. You need to provide the client name when establishing * a new session, often this is the name that will be used by the participant. */ const openSession = async (sessionName) => { console.group("Step 2: Open a Session"); console.log(`Session Name: ${sessionName}`); try { await VoxeetSDK.session.open({ name: sessionName }); shareMessage("Step 2: Session opened."); } catch (error) { console.error(error); shareMessage(`Error opening session: ${error}`); } console.groupEnd(); } /** * Bi-directional communications for multiple participants occurs in a conference. Initially, * the conference must be created before it can be joined. The conference should be given a * unique and meaningful alias to help identify it among multiple conferences in an account. * * This should be in response to a user event so that they may approve media access to the * microphone and camera. */ const createAndJoinConference = async (conferenceAlias, participantName) => { if (!VoxeetSDK.session.isOpen()) { await openSession(participantName); }; console.group("Step 3: Create and Join a Conference"); console.log(`Conference Alias: ${conferenceAlias}`); const joinOptions = { constraints: { audio: true, video: true } }; const conferenceOptions = { alias: conferenceAlias } try { const conference = await VoxeetSDK.conference.create(conferenceOptions); await VoxeetSDK.conference.join(conference, joinOptions); shareMessage(`Step 3: Conference '${conferenceAlias}' created and joined.`) } catch (error) { console.error(error); } console.groupEnd(); }; /** * The SDK will trigger server-generated events which we can respond to * for intended functionality. */ const handleConferenceFlow = () => { // Custom behavior for when there is a media stream added VoxeetSDK.conference.on("streamAdded", (participant, stream) => { console.log(`Stream Added for ${participant.info.name}`); console.log(` Type: ${stream.type}`); console.log(` Video Tracks: ${stream.getVideoTracks().length}`); if (stream.type === "Camera") { shareVideo(participant, stream); } }); // Custom behavior for when there is a media stream updated which happens once an attendee starts sharing video VoxeetSDK.conference.on("streamUpdated", (participant, stream) => { console.log(`Stream Updated for ${participant.info.name}`); console.log(` Type: ${stream.type}`); console.log(` Video Tracks: ${stream.getVideoTracks().length}`); if (stream.type === "Camera" && stream.getVideoTracks().length) { shareVideo(participant, stream); } }); // Custom behavior for when the app stops receiving a media stream for remote participants VoxeetSDK.conference.on("streamRemoved", (participant, stream) => { console.log(`Stream Removed for ${participant.info.name}`); const videoNode = document.getElementById(`video-${participant.id}`); if (videoNode) { videoNode.parentNode.removeChild(videoNode); } }); // Custom behavior for when the participant has left the conference VoxeetSDK.conference.on("left", async () => { await VoxeetSDK.session.close(); console.log("Session closed."); }); } /** * When a new participant camera media stream is detected, we determine which * part of the user interface to update and create a video element that will * display the incoming stream. */ const shareVideo = (participant, stream) => { console.group("Step 4: Start and Share Video"); let perspective = "self-view"; if (VoxeetSDK.session.participant.id !== participant.id) { console.log("Adding media stream for remote user."); perspective = "remote-view"; } let videoNode = document.getElementById(`video-${participant.id}`); if (videoNode) { console.log("Video node already created"); } else { console.log(`Creating a video node: video-${participant.id}`); videoNode = document.createElement("video"); videoNode.setAttribute("id", `video-${participant.id}`); videoNode.setAttribute("height", "100%"); videoNode.setAttribute("width", "100%"); videoNode.muted = true; // Don't echo local audio videoNode.autoplay = true; // Start right away videoNode.playsinline = true; // Not full screen const videoContainer = document.getElementById(perspective); videoContainer.lastElementChild.replaceWith(videoNode); videoContainer.firstElementChild.innerText = participant.info.name; } navigator.attachMediaStream(videoNode, stream); shareMessage(`Step 4: Video of participant '${participant.info.name}' started.`); console.groupEnd(); } /** * When the user decides to leave the conference you should stop sending the audio/video * stream. */ const leaveConference = async () => { console.group("Final Step: Leave the Conference"); try { await VoxeetSDK.conference.leave(); shareMessage("Getting Started Success: Conference has ended.") } catch (error) { console.error(error); } console.groupEnd(); } const main = async () => { // When the web page has finished loading, configure Auth0 client, check the user's login state, and update the UI accordingly. window.onload = async () => { await configureClient(); await processLoginState(); // Function below will use initializeToken and openSession functions as callbacks in it after authentication. await updateUI(initializeToken, openSession); }; // When user clicks the Log in button, redirect user to Auth0 to access the conference only after authentication document.getElementById("btn-login").onclick = async () => { await login(); }; // When user clicks the Log out button, log out and clean Auht0 browser cookies document.getElementById("btn-logout").onclick = async () => { await logout(); }; // Configure the conference alias from query parameter values const queryParams = new URLSearchParams(window.location.search); const alias = queryParams.get("alias") || "web-sdk-starter"; // When user clicks the Join button, start and join a conference for the given alias document.getElementById("btn-join").onclick = async () => { await createAndJoinConference(alias); }; // Define custom behavior for activity that occurs during a video call handleConferenceFlow(); // When user clicks the Invite button, generate a url to join the same conference document.getElementById("btn-invite").onclick = () => { console.group("Step 5: Invite a remote participant") let url = `http://localhost:3000/?alias=${alias}`; console.log(`Invite a guest with URL: ${url}`); shareMessage(`Share the URL copied to your browser clipboard: ${url}`); navigator.clipboard.writeText(url); console.groupEnd(); } // When user clicks the Leave button, end the conference document.getElementById("btn-leave").onclick = async () => { await leaveConference(); console.log("Getting Started Guide complete, congratulations!"); }; }; main(); </script> </body> </html>
尋找差異