PHP Classes

File: resources/assets/js/components/ChatRoom.vue

Recommend this page to a friend!
  Classes of Nyi Nyi Lwin   Laravel Video Chat   resources/assets/js/components/ChatRoom.vue   Download  
File: resources/assets/js/components/ChatRoom.vue
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: Laravel Video Chat
Multiuser video chat using Socket.IO and WebRTC
Author: By
Last change: Add File Preview Component

Add File Sharing

Date: 7 years ago
Size: 17,432 bytes
 

Contents

Class file image Download
<template> <div> <div class="row"> <div class="col-md-6"> <div class="panel panel-primary"> <div class="panel-heading"> <span class="glyphicon glyphicon-comment"></span> Chat with {{ withUser.name }} <button class="btn btn-warning btn-sm pull-right" @click="startVideoCallToUser(withUser.id)" type="button"> <span class="fa fa-video-camera"></span> Video Call </button> </div> <div class="panel-body"> <ul class="chat" v-chat-scroll> <li class="clearfix" v-for="message in messages" v-bind:class="{ 'right' : check(message.sender.id), 'left' : !check(message.sender.id) }"> <span class="chat-img" v-bind:class="{ 'pull-right' : check(message.sender.id) , 'pull-left' : !check(message.sender.id) }"> <img :src="'http://placehold.it/50/FA6F57/fff&text='+ message.sender.name" alt="User Avatar" class="img-circle" /> </span> <div class="chat-body clearfix"> <div class="header"> <small class=" text-muted"><span class="glyphicon glyphicon-time"></span><timeago :since="message.created_at" :auto-update="10"></timeago></small> <strong v-bind:class="{ 'pull-right' : check(message.sender.id) , 'pull-left' : !check(message.sender.id)}" class="primary-font"> {{ message.sender.name }} </strong> </div> <p v-bind:class="{ 'pull-right' : check(message.sender.id) , 'pull-left' : !check(message.sender.id)}"> {{ message.text }} </p> <div class="row"> <file-preview :file="file" v-for="file in message.files" :key="file.id"></file-preview> </div> </div> </li> </ul> </div> <div class="panel-footer"> <div class="input-group"> <input id="btn-input" type="text" v-model="text" class="form-control input-sm" placeholder="Type your message here..." /> <span class="input-group-btn"> <button class="btn btn-warning btn-sm" type="button" @click.prevent="send()" id="btn-chat"> Send </button> </span> </div> <div class="input-group"> <input type="file" multiple class="form-control"> <span class="input-group-btn"> <button class="btn btn-warning btn-sm" type="button" @click.prevent="sendFiles()"> Send Files </button> </span> </div> </div> </div> </div> <div class="col-md-6"> <video-section></video-section> </div> <div id="incomingVideoCallModal" class="modal fade" role="dialog"> <div class="modal-dialog"> <!-- Modal content--> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal">&times;</button> <h4 class="modal-title">Incoming Call</h4> </div> <div class="modal-footer"> <button type="button" id="answerCallButton" class="btn btn-success">Answer</button> <button type="button" id="denyCallButton" data-dismiss="modal" class="btn btn-danger">Deny</button> </div> </div> </div> </div> </div> <div class="row"> <file-preview :file="file" v-for="file in conversation.files" :key="file.id"></file-preview> </div> </div> </template> <script> $(function () { var localVideo = document.getElementById('localVideo'); var remoteVideo = document.getElementById('remoteVideo'); var answerButton = document.getElementById('answerCallButton'); answerButton.onclick = answerCall; $('input[type=file]').on('change', prepareUpload); }); var files; var conversationID; var luid; var ruid; var startTime; var localStream; var pc; var offerOptions = { offerToReceiveAudio: 1, offerToReceiveVideo: 1 }; var isCaller = false; var peerConnectionDidCreate = false; var candidateDidReceived = false; export default { props: ['conversation' , 'currentUser'], data() { return { conversationId : this.conversation.conversationId, channel : this.conversation.channel_name, messages : this.conversation.messages, withUser : this.conversation.user, text : '', constraints : { audio: false, video: true }, } }, methods: { startVideoCallToUser (id) { Cookies.set('remoteUUID', id); window.remoteUUID = id; luid = Cookies.get('uuid'); ruid = Cookies.get('remoteUUID'); isCaller = true; start() }, check(id) { return id === this.currentUser.id; }, send() { axios.post('/chat/message/send',{ conversationId : this.conversationId, text: this.text, }).then((response) => { this.text = ''; }); }, sendFiles() { var data = new FormData(); $.each(files, function(key, value) { data.append('files[]', value); }); data.append('conversationId' , this.conversationId); axios.post('/chat/message/send/file', data); }, listenForNewMessage: function () { Echo.join(this.channel) .here((users) => { console.log(users) }) .listen('\\PhpJunior\\LaravelVideoChat\\Events\\NewConversationMessage', (data) => { var self = this; if ( data.files.length > 0 ){ $.each( data.files , function( key, value ) { self.conversation.files.push(value); }); } this.messages.push(data); }) .listen('\\PhpJunior\\LaravelVideoChat\\Events\\VideoChatStart', (data) => { if(data.to != this.currentUser.id){ return; } if(data.type === 'signal'){ onSignalMessage(data); }else if(data.type === 'text'){ console.log('received text message from ' + data.from + ', content: ' + data.content); }else{ console.log('received unknown message type ' + data.type + ' from ' + data.from); } }); }, }, beforeMount () { Cookies.set('uuid', this.currentUser.id); Cookies.set('conversationID', this.conversationId); }, mounted() { this.listenForNewMessage(); } } function onSignalMessage(m){ console.log(m.subtype); if(m.subtype === 'offer'){ console.log('got remote offer from ' + m.from + ', content ' + m.content); Cookies.set('remoteUUID', m.from); onSignalOffer(m.content); }else if(m.subtype === 'answer'){ onSignalAnswer(m.content); }else if(m.subtype === 'candidate'){ onSignalCandidate(m.content); }else if(m.subtype === 'close'){ onSignalClose(); }else{ console.log('unknown signal type ' + m.subtype); } } function onSignalClose() { trace('Ending call'); pc.close(); pc = null; closeMedia(); clearView(); } function closeMedia(){ localStream.getTracks().forEach(function(track){track.stop();}); } function clearView(){ localVideo.srcObject = null; remoteVideo.srcObject = null; } function onSignalCandidate(candidate){ onRemoteIceCandidate(candidate); } function onRemoteIceCandidate(candidate){ trace('onRemoteIceCandidate : ' + candidate); if(peerConnectionDidCreate){ addRemoteCandidate(candidate); }else{ //remoteCandidates.push(candidate); var candidates = Cookies.getJSON('candidate'); if(candidateDidReceived){ candidates.push(candidate); }else{ candidates = [candidate]; candidateDidReceived = true; } Cookies.set('candidate', candidates); } } function onSignalAnswer(answer){ onRemoteAnswer(answer); } function onRemoteAnswer(answer){ trace('onRemoteAnswer : ' + answer); pc.setRemoteDescription(answer).then(function(){onSetRemoteSuccess(pc)}, onSetSessionDescriptionError); } function onSignalOffer(offer){ Cookies.set('offer', offer); $('#incomingVideoCallModal').modal('show'); } function answerCall() { isCaller = false; luid = Cookies.get('uuid'); ruid = Cookies.get('remoteUUID'); $('#incomingVideoCallModal').modal('hide'); start() } function gotStream(stream) { trace('Received local stream'); localVideo.srcObject = stream; localStream = stream; call() } function start() { trace('Requesting local stream'); navigator.mediaDevices.getUserMedia({ audio: true, video: { width: { exact: 320 }, height: { exact: 240 } } }) .then(gotStream) .catch(function(e) { alert('getUserMedia() error: ' + e.name); }); } function call() { conversationID = Cookies.get('conversationID'); trace('Starting call'); startTime = window.performance.now(); var videoTracks = localStream.getVideoTracks(); var audioTracks = localStream.getAudioTracks(); if (videoTracks.length > 0) { trace('Using video device: ' + videoTracks[0].label); } if (audioTracks.length > 0) { trace('Using audio device: ' + audioTracks[0].label); } var configuration = { "iceServers": [{ "urls": "stun:stun.ideasip.com" }] }; pc = new RTCPeerConnection(configuration); trace('Created local peer connection object pc'); pc.onicecandidate = function(e) { onIceCandidate(pc, e); }; pc.oniceconnectionstatechange = function(e) { onIceStateChange(pc, e); }; pc.onaddstream = gotRemoteStream; pc.addStream(localStream); trace('Added local stream to pc'); peerConnectionDidCreate = true; if(isCaller) { trace(' createOffer start'); trace('pc createOffer start'); pc.createOffer( offerOptions ).then( onCreateOfferSuccess, onCreateSessionDescriptionError ); }else{ onAnswer() } } function onAnswer(){ var remoteOffer = Cookies.getJSON('offer'); pc.setRemoteDescription(remoteOffer).then(function(){onSetRemoteSuccess(pc)}, onSetSessionDescriptionError); pc.createAnswer().then( onCreateAnswerSuccess, onCreateSessionDescriptionError ); } function onCreateAnswerSuccess(desc) { trace('Answer from pc:\n' + desc.sdp); trace('pc setLocalDescription start'); pc.setLocalDescription(desc).then( function() { onSetLocalSuccess(pc); }, onSetSessionDescriptionError ); conversationID = Cookies.get('conversationID'); var message = {from: luid, to:ruid, type: 'signal', subtype: 'answer', content: desc, time:new Date()}; axios.post('/trigger/' + conversationID , message ); } function onSetRemoteSuccess(pc) { trace(pc + ' setRemoteDescription complete'); applyRemoteCandidates(); } function applyRemoteCandidates(){ var candidates = Cookies.getJSON('candidate'); for(var candidate in candidates){ addRemoteCandidate(candidates[candidate]); } Cookies.remove('candidate'); } function addRemoteCandidate(candidate){ pc.addIceCandidate(candidate).then( function() { onAddIceCandidateSuccess(pc); }, function(err) { onAddIceCandidateError(pc, err); }); } function onIceCandidate(pc, event) { if (event.candidate){ trace(pc + ' ICE candidate: \n' + (event.candidate ? event.candidate.candidate : '(null)')); conversationID = Cookies.get('conversationID'); var message = {from: luid, to:ruid, type: 'signal', subtype: 'candidate', content: event.candidate, time:new Date()}; axios.post('/trigger/' + conversationID , message ); } } function onAddIceCandidateSuccess(pc) { trace(pc + ' addIceCandidate success'); } function onAddIceCandidateError(pc, error) { trace(pc + ' failed to add ICE Candidate: ' + error.toString()); } function onIceStateChange(pc, event) { if (pc) { trace(pc + ' ICE state: ' + pc.iceConnectionState); console.log('ICE state change event: ', event); } } function onCreateSessionDescriptionError(error) { trace('Failed to create session description: ' + error.toString()); } function onCreateOfferSuccess(desc) { trace('Offer from pc\n' + desc.sdp); trace('pc setLocalDescription start'); pc.setLocalDescription(desc).then( function() { onSetLocalSuccess(pc); }, onSetSessionDescriptionError ); conversationID = Cookies.get('conversationID'); var message = {from: luid, to:ruid, type: 'signal', subtype: 'offer', content: desc, time:new Date()}; axios.post('/trigger/' + conversationID , message ); } function onSetLocalSuccess(pc) { trace( pc + ' setLocalDescription complete'); } function onSetSessionDescriptionError(error) { trace('Failed to set session description: ' + error.toString()); } function gotRemoteStream(e) { if (remoteVideo.srcObject !== e.stream) { remoteVideo.srcObject = e.stream; trace('pc received remote stream'); } } function trace(arg) { var now = (window.performance.now() / 1000).toFixed(3); console.log(now + ': ', arg); } function prepareUpload(event) { files = event.target.files; } </script> <style> .chat { list-style: none; margin: 0; padding: 0; } .chat li { margin-bottom: 10px; padding-bottom: 5px; border-bottom: 1px dotted #B3A9A9; } .chat li.left .chat-body { margin-left: 60px; } .chat li.right .chat-body { margin-right: 60px; } .chat li .chat-body p { margin: 0; color: #777777; } .panel .slidedown .glyphicon, .chat .glyphicon { margin-right: 5px; } .panel-body { overflow-y: scroll; height: 250px; } ::-webkit-scrollbar-track { -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); background-color: #F5F5F5; } ::-webkit-scrollbar { width: 12px; background-color: #F5F5F5; } ::-webkit-scrollbar-thumb { -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3); background-color: #555; } </style>