Noah Petherbridge
3f756c5318
* Two users can activate their cameras locally and then connect them together with WebRTC with video and audio support working! * Limitation: users need to be broadcasting video themselves before they can connect to someone's camera. If the offerer doesn't add tracks of their own, the SDP offer doesn't request video channels; so even though the answerer adds their tracks to the connection, they aren't used by the offerer. * As currently implemented, the offerer's camera feed will also appear on screen for the answerer - every video connection opens the feed both ways. Compared to the previous commit (where clients shared SDP messages but not ICE candidates or anything further) the fixes and learnings were: * The back-end was trying to relay candidate messages, but there was a JSON marshalling error (json object casted into a string) - changed the Message type to map[string]interface{} and both sides could exchange ICE candidates. * Both sides needed to add their video tracks to the connection so that there was anything of value to be sent over the WebRTC channel. Other changes: * Server will send a ping message every minute to connected WebSockets.
252 lines
9.4 KiB
HTML
252 lines
9.4 KiB
HTML
{{define "index"}}
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<link rel="stylesheet" type="text/css" href="/static/css/bulma.min.css">
|
|
<link rel="stylesheet" href="/static/fontawesome-free-6.1.2-web/css/all.css">
|
|
<link rel="stylesheet" type="text/css" href="/static/css/chat.css?{{CacheHash}}">
|
|
<title>BareRTC</title>
|
|
</head>
|
|
<body>
|
|
<div id="BareRTC-App">
|
|
<!-- Sign In modal -->
|
|
<div class="modal" :class="{'is-active': loginModal.visible}">
|
|
<div class="modal-background"></div>
|
|
<div class="modal-content">
|
|
<div class="card">
|
|
<header class="card-header has-background-info">
|
|
<p class="card-header-title has-text-light">Sign In</p>
|
|
</header>
|
|
<div class="card-content">
|
|
<form @submit.prevent="signIn()">
|
|
|
|
<div class="field">
|
|
<label class="label">Username</label>
|
|
<input class="input"
|
|
v-model="username"
|
|
placeholder="Username"
|
|
autocomplete="off"
|
|
autofocus
|
|
required>
|
|
</div>
|
|
|
|
<div class="field">
|
|
<div class="control">
|
|
<button class="button is-link">Submit</button>
|
|
</div>
|
|
</div>
|
|
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="chat-container">
|
|
<div class="left-column">
|
|
<div class="card grid-card">
|
|
<header class="card-header has-background-success-dark">
|
|
<p class="card-header-title has-text-light">
|
|
Channels
|
|
</p>
|
|
</header>
|
|
<div class="card-content">
|
|
<aside class="menu">
|
|
<p class="menu-label">
|
|
Chat Rooms
|
|
</p>
|
|
|
|
<ul class="menu-list">
|
|
<li><a href="#" class="is-active">Chat Room</a></li>
|
|
</ul>
|
|
|
|
<p class="menu-label">
|
|
Private Messages
|
|
</p>
|
|
|
|
<ul class="menu-list">
|
|
<li><a href="#">Chat Room</a></li>
|
|
<li><a href="#">DMs</a></li>
|
|
<li><a href="#">DMs</a></li>
|
|
<li><a href="#">DMs</a></li>
|
|
<li><a href="#">DMs</a></li>
|
|
<li><a href="#">DMs</a></li>
|
|
<li><a href="#">DMs</a></li>
|
|
<li><a href="#">DMs</a></li>
|
|
<li><a href="#">DMs</a></li>
|
|
<li><a href="#">DMs</a></li>
|
|
<li><a href="#">DMs</a></li>
|
|
<li><a href="#">DMs</a></li>
|
|
<li><a href="#">DMs</a></li>
|
|
<li><a href="#">DMs</a></li>
|
|
<li><a href="#">DMs</a></li>
|
|
<li><a href="#">DMs</a></li>
|
|
<li><a href="#">DMs</a></li>
|
|
<li><a href="#">DMs</a></li>
|
|
<li><a href="#">DMs</a></li>
|
|
<li><a href="#">DMs</a></li>
|
|
</ul>
|
|
</aside>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="chat-column">
|
|
<div class="card grid-card">
|
|
<header class="card-header has-background-link">
|
|
<p class="card-header-title has-text-light">
|
|
Chat Room
|
|
</p>
|
|
</header>
|
|
<div class="video-feeds">
|
|
<video class="feed"
|
|
v-show="webcam.active"
|
|
id="localVideo"
|
|
autoplay muted>
|
|
x
|
|
</video>
|
|
<video class="feed"
|
|
v-for="(stream, username) in WebRTC.streams"
|
|
v-bind:key="username"
|
|
:id="'videofeed-'+username"
|
|
autoplay muted>
|
|
</video>
|
|
<div v-for="(stream, username) in WebRTC.streams" class="feed">
|
|
[[username]] - [[stream]]
|
|
</div>
|
|
<div class="feed">
|
|
y
|
|
</div>
|
|
<div class="feed">
|
|
y
|
|
</div>
|
|
<div class="feed">
|
|
y
|
|
</div>
|
|
<div class="feed">
|
|
y
|
|
</div>
|
|
<div class="feed">
|
|
y
|
|
</div>
|
|
<div class="feed">
|
|
y
|
|
</div>
|
|
<div class="feed">
|
|
y
|
|
</div>
|
|
<div class="feed">
|
|
y
|
|
</div>
|
|
<div class="feed">
|
|
y
|
|
</div>
|
|
<div class="feed">
|
|
y
|
|
</div>
|
|
<div class="feed">
|
|
y
|
|
</div>
|
|
<div class="feed">
|
|
y
|
|
</div>
|
|
</div>
|
|
<div class="card-content" id="chatHistory">
|
|
|
|
<div v-for="(msg, i) in history" v-bind:key="i">
|
|
<div>
|
|
<label class="label"
|
|
:class="{'has-text-success is-dark': msg.isChatServer,
|
|
'has-text-warning is-dark': msg.isAdmin,
|
|
'has-text-danger': msg.isChatClient}">
|
|
[[msg.username]]
|
|
</label>
|
|
</div>
|
|
|
|
<div v-if="msg.action === 'presence'">
|
|
<em>[[msg.message]]</em>
|
|
</div>
|
|
<div v-else>
|
|
[[msg.message]]
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="chat-footer">
|
|
<div class="card">
|
|
<div class="card-content p-2">
|
|
|
|
<div class="columns">
|
|
<div class="column">
|
|
<form @submit.prevent="sendMessage()">
|
|
<input type="text" class="input"
|
|
v-model="message"
|
|
placeholder="Message">
|
|
</form>
|
|
</div>
|
|
<div class="column is-narrow">
|
|
<button type="button"
|
|
v-if="webcam.active"
|
|
class="button is-danger"
|
|
@click="stopVideo()">
|
|
<i class="fa fa-camera mr-2"></i>
|
|
Stop
|
|
</button>
|
|
|
|
<button type="button"
|
|
v-else
|
|
class="button is-success"
|
|
@click="startVideo()"
|
|
:disabled="webcam.busy">
|
|
<i class="fa fa-camera mr-2"></i>
|
|
Start
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="right-column">
|
|
<div class="card grid-card">
|
|
<header class="card-header has-background-success-dark">
|
|
<p class="card-header-title has-text-light">
|
|
Who Is Online
|
|
</p>
|
|
</header>
|
|
<div class="card-content p-2">
|
|
|
|
<ul class="menu-list">
|
|
<li v-for="(u, i) in whoList" v-bind:key="i">
|
|
<div class="columns is-mobile">
|
|
<div class="column">[[ u.username ]]</div>
|
|
<div class="column is-narrow">
|
|
<button type="button" class="button is-small"
|
|
:disabled="!u.videoActive"
|
|
@click="openVideo(u)">
|
|
<i class="fa fa-video"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div><!-- /app -->
|
|
<script src="/static/js/vue-3.2.45.js"></script>
|
|
<script src="/static/js/BareRTC.js?{{CacheHash}}"></script>
|
|
|
|
</body>
|
|
</html>
|
|
{{end}} |