[deploy] A bit more video experimentation (#7110)

This commit is contained in:
Ben Halpern 2020-04-06 17:16:41 -04:00 committed by GitHub
parent be3a259b8e
commit 41c2e2c1b9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 116 additions and 114 deletions

View file

@ -5,19 +5,20 @@ class VideoChatsController < ApplicationController
account_sid = ApplicationConfig["TWILIO_ACCOUNT_SID"]
api_key = ApplicationConfig["TWILIO_VIDEO_API_KEY"]
api_secret = ApplicationConfig["TWILIO_VIDEO_API_SECRET"]
@username = "@" + current_user.username
token = Twilio::JWT::AccessToken.new(
account_sid,
api_key,
api_secret,
[],
identity: current_user.id,
identity: @username,
)
grant = Twilio::JWT::AccessToken::VideoGrant.new
grant.room = params[:id]
token.add_grant(grant)
@username = @username
@token = token.to_jwt
end
end

View file

@ -1,119 +1,78 @@
import { h, Component, render } from 'preact';
import PropTypes from 'prop-types';
const { createLocalVideoTrack, connect } = require('twilio-video');
const root = document.getElementById('chat');
const muteButton = document.getElementById('mute-toggle');
const videoToggleButton = document.getElementById('videohide-toggle')
connect(root.dataset.token, { name: 'room-name', audio: true, type: 'peer-to-peer', video: { width: 640 } }).then(room => {
room.participants.forEach(participantConnected);
room.on('participantConnected', participantConnected);
const root = document.getElementById('chat')
room.on('participantDisconnected', participantDisconnected);
room.once('disconnected', error => room.participants.forEach(participantDisconnected));
export default class VideoChat extends Component {
componentDidMount() {
this.setupCallChannel(root.dataset.token)
muteButton.onclick = function(e) {
e.preventDefault();
room.localParticipant.audioTracks.forEach(function(trackPub) {
if (muteButton.dataset.muted === 'true') {
muteButton.dataset.muted = 'false'
trackPub.track.enable();
} else {
muteButton.dataset.muted = 'true'
trackPub.track.disable();
}
});
}
setupCallChannel = token => {
const component = this;
const activeChannelId = root.dataset.channel
console.log()
import('twilio-video').then(({ connect, createLocalVideoTrack }) => {
connect(
token,
{
name: `private-video-channel-${activeChannelId}`,
audio: true,
type: 'peer-to-peer',
video: { width: 640 },
},
).then(
function onConnectSuccess(room) {
console.log(room)
component.setState({ token: token, room });
createLocalVideoTrack().then(track => {
const localMediaContainer = document.getElementById(
'videolocalscreen',
);
localMediaContainer.appendChild(track.attach());
});
const roomParticipants = [];
room.participants.forEach(participant => {
component.triggerRemoteJoin(participant);
roomParticipants.push(participant);
});
component.setState({ participants: roomParticipants });
room.on('participantConnected', function onParticipantConnected(
participant,
) {
console.log('participant joined')
component.triggerRemoteJoin(participant);
room.participants.forEach(p => {
roomParticipants.push(p);
});
component.setState({ participants: roomParticipants });
room.on(
'participantDisconnected',
function onParticipantDisconnected() {
console.log('disconnected')
},
);
participant.on('dominantSpeakerChanged', dominantSpeaker => {
// eslint-disable-next-line no-console
console.log(
'The new dominant speaker in the Room is:',
dominantSpeaker,
);
});
});
},
function onConnectFailure(error) {
document.getElementById('videoremotescreen').innerHTML = '';
// eslint-disable-next-line no-console
console.error(`Unable to connect to Room: ${error.message}`);
},
);
});
};
triggerRemoteJoin = participant => {
participant.on('trackSubscribed', track => {
console.log(track)
if (!document.getElementById(`${track.kind}-${track.id}`)) {
const trackDiv = document.createElement('div');
trackDiv.className = `chat__videocalltrackdiv--${track.kind}`;
trackDiv.id = participant.sid;
trackDiv.appendChild(track.attach());
document.getElementById('videoremotescreen').appendChild(trackDiv);
document.getElementById(
'videoremotescreen',
).lastChild.id = `${track.kind}-${track.sid}`;
videoToggleButton.onclick = function(e) {
e.preventDefault();
room.localParticipant.videoTracks.forEach(function(trackPub) {
if (videoToggleButton.dataset.hidden === 'true') {
videoToggleButton.dataset.hidden = 'false'
trackPub.track.enable();
} else {
videoToggleButton.dataset.hidden = 'true'
trackPub.track.disable();
}
});
participant.on('trackRemoved', track => {
if (document.getElementById(track.id)) {
document.getElementById(track.id).outerHTML = '';
}
});
// participant.on('trackDisabled', track => {
// console.log('disabled')
// console.log('TODO: Show track status on video')
// console.log(track.mediaStreamTrack.id)
// });
// participant.on('trackEnabled', track => {
// console.log('enabled')
// console.log('TODO: Show track status on video')
// console.log(track.mediaStreamTrack.id)
// });
};
render() {
return <div>
<div id="videoremotescreen"></div>
<div id="videolocalscreen"></div>
</div>
});
}
});
createLocalVideoTrack().then(track => {
const localMediaContainer = document.getElementById('local-media');
localMediaContainer.appendChild(track.attach());
});
function participantConnected(participant) {
const div = document.createElement('div');
div.id = participant.sid;
div.className = "individual-video"
div.innerHTML = '<div class="participant-name">'+ participant.identity + '</div>'
participant.on('trackSubscribed', track => trackSubscribed(div, track));
participant.on('trackUnsubscribed', trackUnsubscribed);
participant.tracks.forEach(publication => {
if (publication.isSubscribed) {
trackSubscribed(div, publication.track);
}
});
root.appendChild(div);
}
function participantDisconnected(participant) {
console.log('Participant "%s" disconnected', participant.identity);
document.getElementById(participant.sid).remove();
}
render(<VideoChat />, root, root.firstElementChild);
function trackSubscribed(div, track) {
div.appendChild(track.attach());
}
function trackUnsubscribed(track) {
track.detach().forEach(element => element.remove());
}

View file

@ -1,9 +1,51 @@
<div class="video-chat-wrapper" id="chat" data-token="<%= @token %>" data-channel="<%= params[:id] %>">
<style>
.video-chat-wrapper {
position: relative;
height: 95vh;
background: black;
overflow: scroll;
}
video {
border-radius: 8px;
}
.individual-video video {
width: 96%;
max-width: 800px;
margin: 2%;
}
#local-media video {
width: 130px;
position: absolute;
bottom: 10px;
right: 10px;
}
.individual-video {
position: relative;
}
.participant-name {
background: black;
padding: 3px 8px;
border-radius: 3px;
position: absolute;
bottom: 4%;
left: 3%;
color: white;
font-size: 16px;
}
.video-controls {
position: absolute;
bottom: 10px;
left: 10px;
}
</style>
<div class="video-chat-wrapper" id="chat" data-token="<%= @token %>" data-channel="<%= params[:id] %>" data-user="<%= @username %>">
<div id="remote-media"></div>
<div id="local-media"></div>
<div class="video-controls">
<button id="mute-toggle" data-muted="false">Mute</button>
<button id="videohide-toggle" data-hidden="false">Hide Video</button>
</div>
<h1>This is an experiment</h1>
<h3>It's only a partially implemented view.</h3>
<h4>But this could be a more straightforward way to do video chat within /connect.</h4>
<%# TODO Make paramsp[:id] map to a chat channel and ensure the users have permission %>
<%# That part is pretty straightforward %>
<%# Then close the loop on the JavaScript part of it. %>