[deploy] A bit more video experimentation (#7110)
This commit is contained in:
parent
be3a259b8e
commit
41c2e2c1b9
3 changed files with 116 additions and 114 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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. %>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue