diff --git a/app/controllers/video_chats_controller.rb b/app/controllers/video_chats_controller.rb index 09f86ac63..c8262322c 100644 --- a/app/controllers/video_chats_controller.rb +++ b/app/controllers/video_chats_controller.rb @@ -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 diff --git a/app/javascript/packs/videoChat.jsx b/app/javascript/packs/videoChat.jsx index c7a47fd89..c9cdd1a0d 100644 --- a/app/javascript/packs/videoChat.jsx +++ b/app/javascript/packs/videoChat.jsx @@ -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
-
-
-
+ }); } +}); + + +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 = '
'+ participant.identity + '
' + + 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(, root, root.firstElementChild); +function trackSubscribed(div, track) { + div.appendChild(track.attach()); +} + +function trackUnsubscribed(track) { + track.detach().forEach(element => element.remove()); +} diff --git a/app/views/video_chats/show.html.erb b/app/views/video_chats/show.html.erb index a385459ea..65d56212c 100644 --- a/app/views/video_chats/show.html.erb +++ b/app/views/video_chats/show.html.erb @@ -1,9 +1,51 @@ -
+ +
+
+
+
+ +
-

This is an experiment

-

It's only a partially implemented view.

-

But this could be a more straightforward way to do video chat within /connect.

<%# 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. %>