Crie um app de chat por vídeo com JavaScript, Vue.js e Programmable Video

August 30, 2018
Escrito por
Onwuka Gideon
Contribuidor
As opiniões expressas pelos colaboradores da Twilio são de sua autoria

Crie um app de chat por vídeo com JavaScript, Vue.js e Programmable Video

This article is for reference only. We're not onboarding new customers to Programmable Video. Existing customers can continue to use the product until December 5, 2024.


We recommend migrating your application to the API provided by our preferred video partner, Zoom. We've prepared this migration guide to assist you in minimizing any service disruption.

Vue.js é uma estrutura JavaScript poderosa e acessível que se concentra na criação de interfaces de usuário. Gosto do Vue porque ele se adapta com facilidade. Neste artigo, mostrarei como criar um aplicativo de chat por vídeo usando Vue.js e o Twilio Programmable Video. No app, os participantes fornecerão um nome de usuário para obter acesso ao app de chat e, em seguida, ingressarão em uma sala (à esquerda da captura de tela abaixo) para iniciar o chat.

Aqui está uma prévia do que vamos criar:

GIF com animação da tela funcional do exemplo que vamos desenvolver.

Pré-requisitos

O conhecimento básico dos itens a seguir será útil, mas não é necessário ter um amplo conhecimento:

Antes de continuar, verifique se o Node.js está instalado no sistema.

Obter chaves de API da Twilio

A primeira etapa para usar o bate-papo do Twilio Programmable Video é obter um access token (token de acesso). A Twilio gerará um token usando suas API Keys (chaves de API). A Twilio usa esse token para garantir que as pessoas que usam seu app estejam autorizadas a fazê-lo.

Para obter suas chaves de API da Twilio, faça login ou inscreva-se para abrir uma conta gratuita. Depois de fazer login, anote o ACCOUNT SID (SID da Conta) no seu dashboard.

Tela do console da Twilio com as informações das chaves da API.

Em seguida, vá para All Products & Services (Todos os produtos e serviços), clicando no ícone à esquerda, conforme mostrado na imagem abaixo:

Tela parcial do console da Twilio marcando os 'três pontinhos' para acessar todos os produtos.

No pop-up exibido, clique em Programmable Video. O dashboard Programmable Video será carregado para você.

Em seguida, clique em Tools (Ferramentas) depois em API Keys (Chaves de API) e, em seguida, clique no ícone +, como mostrado na imagem abaixo:

Tela do console da Twilio com o botão de criação de uma nova API Key.

Por fim, insira um nome fácil de lembrar no campo de entrada FRIENDLY NAME (Nome fácil de lembrar) e clique em Create API Key (Criar chave de API).

Tela parcial do console da Twilio com o formulário para criar uma nova API Key.

A página que será carregada contém suas API Keys (chaves de API). Anote sua SID key (chave SID) de API, sua SECRET key (chave Secreta) e também seu ACCOUNT SID (SID da conta). Usaremos essas chaves na próxima seção.

Gerar o token de acesso

Escrevi um app Node.js básico para gerar tokens. Vá em frente e clone o repositório no Github e, em seguida, inicie-o. Você encontrará instruções sobre como instalar e executar o app no arquivo Readme. Você precisará de suas chaves de API.

 Você pode usar qualquer linguagem de programação para gerar o token, desde que tenha suas chaves de API da Twilio.

Após a instalação, certifique-se de manter o servidor em execução. Vamos nos conectar ao servidor para gerar o token mais tarde.

Configurar o app Vue

O Vue fornece uma CLI oficial para desenvolver um novo projeto Vue.js. Primeiro, você precisará instalar o Vue CLI globalmente em seu sistema (se ainda não o tiver instalado). Em seguida, você criará um novo projeto Vue com os comandos CLI.

Para criar um novo projeto Vue, execute os seguintes comandos no prompt de comando:

# Install vue cli globally on your system
$ npm install -g @vue/cli

# Create a new vue project (In the prompt that appears, press enter to select the default preset.)
$ vue create video-chat

# Change your directory to the project directory
$ cd video-chat

# Run the app!
$ npm run serve

Se tudo tiver corrido bem, sua saída final da linha de comando deve ser semelhante a esta:

Parcial da tela do terminal com o resultado do código executado.

Agora, o site http://localhost:8080 levará você a uma página padrão do Vue que indica que a configuração foi concluída e bem-sucedida. Enquanto a compilação está em execução, abra um novo terminal a partir do qual você pode instalar dependências. Além disso, certifique-se de alterar seu diretório para o diretório raiz do projeto.

Instalar dependências

A Twilio fornece um SDK JavaScript que facilita a comunicação com sua API de Programmable Video.

Adicione o SDK JavaScript da Twilio ao projeto executando o comando abaixo:

   $ npm install twilio-video

Usaremos o módulo axios para fazer solicitações ao nosso servidor para um token de acesso. Adicione o módulo axios executando o comando abaixo:

 $ npm install axios

Verifique se você está na pasta raiz do projeto antes de executar os comandos.

Visão geral da API Twilio Programmable Video

Agora que tudo está configurado, vamos definir alguns termos associados à API Twilio Programmable Video:

  • Room (Sala): representa uma sessão de áudio, vídeo e/ou compartilhamento de tela em tempo real.
  • Peer-to-peer Room (Sala ponto a ponto): este é um tipo de sala em que a mídia flui diretamente entre os participantes. Ela aceita até 10 participantes.
  • Group Room (Sala de grupo): este é um tipo de sala em que a mídia é roteada pelos servidores de mídia da Twilio. Esta sala acomoda até 50 participantes.
  • Participants (Participantes): representa aplicativos clientes que estão conectados a uma sala e compartilham mídia de áudio e/ou vídeo entre si.
  • Tracks (Faixas): representa os fluxos individuais de mídia de áudio e vídeo que são compartilhados em uma Sala.
  • Local Tracks (Faixas locais): representa o áudio e o vídeo capturados do microfone e da câmera local.
  • RemoteVideoTracks (Faixas de vídeo remoto): representa as faixas de áudio e vídeo de outros participantes conectados à sala.

Compor a interface de chat

É hora de começar a criar a interface para nosso app. Usaremos o Bootstrap para ajudar a criar o app. Para adicionar o Bootstrap ao projeto, atualize o código em public/index.html com o seguinte:

<!DOCTYPE html>
<html>
 <head>
   <meta charset="utf-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width,initial-scale=1.0">
   <link rel="icon" href="<%= BASE_URL %>favicon.ico">
   <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
   <title>video-chat</title>
 </head>
 <body>
   <noscript>
     <strong>We're sorry but video-chat doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
   </noscript>
   <div id="app"></div>
   <!-- built files will be auto injected -->
 </body>
</html>

Aqui, adicionamos o bootstrap css, pois ele será usado para projetar nosso app.

No Vue, os componentes são elementos do app completo que encapsulam o código reutilizável. A próxima coisa que faremos é dividir nosso app em componentes menores para que possamos criá-los separadamente:

Tela do exemplo marcando os componentes utilizados no projeto. Cada bloco marcado em vermelho corresponde a um item no texto a seguir.

Na imagem acima, temos:

  • [1] - Nosso principal componente que abrigará outros componentes. Geralmente, esse é o arquivo App.vue.
  • [2] - Componente Video. O componente que usaremos para listar o local das faixas remotas.
  • [3] - Componente AddRoom. Componente para adicionar novas salas.
  • [4] - Componente Rooms. Componente para listagem de salas.
  • [5] - Componente Logs. Para exibir registros.

Vamos criar esse componente nas próximas seções.

Acionar e escutar eventos

Antes de começarmos a criar nossos componentes, vamos falar sobre como nossos componentes interagirão uns com os outros.

Às vezes, os componentes filhos precisam se comunicar uns com os outros. Por exemplo, o componente AddRoom conterá um formulário que será usado para criar uma nova sala e o componente Rooms precisa saber quando um formulário de sala é enviado para que possa ser listado.

Quando o usuário envia uma nova sala para ser criada no componente AddRoom, nosso app envia um trigger (acionador) para o componente Rooms para que ele saiba o que aconteceu e tome uma ação.

Isso pode ser feito usando o event bus, que é uma instância do Vue.

Crie um novo arquivo chamado Event.js na pasta src e adicione o seguinte código a ele:

import Vue from 'vue'

export const EventBus = new Vue()

Aqui, estamos exportando uma instância do Vue.

Quando houver a necessidade de acionar ou ouvir um evento em um componente, importaremos o arquivo Event.js.

Reunir todos os componentes

Embora ainda não tenhamos criado nenhum componente, faz sentido reunir todos os componentes que criaremos agora. Para que, ao desenvolver, você possa ver as alterações.

Agora, vamos reunir todos os componentes que criaremos. Importaremos todos os componentes para o App.vue, que é o arquivo do componente de entrada principal.

Atualize src/App.vue com o seguinte código:

<template>
 <div class="container-fluid chat_container" id="app">
     <div class="row" v-if="authenticated">
       <Rooms />
       <Video :username="username"/>
       <Logs />
     </div>
     <div class="row" v-else>
       <div class="username">
           <form class="form-inline" @submit.prevent="submitUsername(username)">
             <div class="form-group mb-2">
                 <input type="text" class="form-control" v-model="username" >
             </div>
             <button type="submit" class="btn btn-primary mb-2 Botton">Submit</button>
         </form>
       </div>
     </div>
 </div>
</template>

Aqui, você verá que adicionamos - <Rooms /><Video> e o componente <Logs />.

Além disso, usamos a diretiva v-if para determinar qual visualização exibir ao usuário quando ele carregar o app. Como precisamos de um nome de usuário para criar um token de acesso para cada usuário, depois que ele abrir o app, exibiremos um formulário para que ele forneça seu nome de usuário.

Assim que ele inserir um nome de usuário, exibiremos a visualização do app para bate-papo. O app usa os dados authenticated (autenticados) para determinar qual visualização deve ser exibida. Ainda não declaramos os dados authenticated (autenticados), mas faremos isso em seguida.

Além disso, passamos o nome de usuário fornecido pelo usuário para o componente Video como property (propriedade).

Em seguida, adicione o seguinte código a src/App.vue imediatamente após a tag de fechamento </template>:

<script>
// import components
import Rooms from './components/Rooms'
import Video from './components/Video'
import Logs from './components/Logs'
import AddRoom from './components/AddRoom'

export default {
 name: 'App',
 data() {
   return {
     username: "",
     authenticated: false
   }
 },
 components: {
   Rooms,
   Video,
   Logs,
   AddRoom
 },
 methods: {
   submitUsername(username) {
      if(!username) {
        return alert('please provide a username');
      }

      this.authenticated = true;
   }
 }
 }
</script>

<style>
 #app {
   font-family: 'Avenir', Helvetica, Arial, sans-serif;
   -webkit-font-smoothing: antialiased;
   -moz-osx-font-smoothing: grayscale;
   text-align: center;
   color: #2c3e50;
   margin-top: 60px;
   background: #2c3e50;
 }
 .box {
   border: 1px solid gray;
 }

 .username {
   margin: 12px auto 7px auto;
   color: wheat;
 }

   .Botton {
   color: #fff;
   background-color: #4d555f;
   border-color: #303840;
   padding: 8px;
   font-weight: bolder;
 }
</style>

Primeiro, importamos todos os componentes que criaremos para este arquivo.

No método data, observe que o nome de usuário está em branco e que authenticated é false (falso). Quando o usuário inserir seu nome de usuário, atualizaremos os dados do nome. Em seguida, se o nome de usuário fornecido for válido (e não em branco, como é o nosso caso), vamos definir authenticated como true (verdadeiro).

Assim que os dados authenticated são definidos como true (verdadeiros), o usuário poderá iniciar o bate-papo.

NOTA: você receberá um erro na página quando visitar http://localhost:8080/. Não há problema em obter erros por enquanto, porque ainda não criamos os componentes que importamos.

Componente AddRoom

Em seguida, vamos criar o componente AddRoom, que conterá um formulário para adicionar uma nova sala.

Crie um novo arquivo chamado AddRoom.vue na pasta src/components e adicione o seguinte código a ele:

<template>
   <div class="row roomForm">
       <form class="form-inline" @submit.prevent="createNewRoom(room_name)">
           <div class="form-group mb-2">
               <input type="text" class="form-control" v-model="room_name" >
           </div>
           <button type="submit" class="btn btn-primary mb-2 createRoomBotton">Create Room</button>
       </form>
   </div>
</template>

<script>
import { EventBus } from '../Event'

export default {
 name: "AddRoom", // Component name
 data() {
   return {
    room_name: "",
   }
 },
 methods: {
   createNewRoom(name) {
       if(!name) {
         alert("please provide a room name");
         return
       }

       this.room_name = '';
       EventBus.$emit('new_room', name);
   }
 }
}
</script>

<style>
 .roomForm {
     margin-left: auto;
     margin-right: auto;
     margin-top: 30px;
     width: 100%;
 }
 .createRoomBotton {
   color: #fff;
   background-color: #4d555f;
   border-color: #303840;
   padding: 8px;
   font-weight: bolder;
 }
</style>

Se você já sabe usar o Vue, deve ter uma ideia do que está acontecendo aqui. Essa é uma das maneiras de criar um componente Vue conhecido como single file component.

Aqui temos três seções: <template><script> e <style>. Todos os elementos HTML vão para a tag <template>, todo o código JavaScript vai para a tag <script> e o estilo do componente vai para a tag <style>.

Além disso, usaremos a diretiva v-model para criar vinculações de dados bidirecionais para a entrada de formulário. A diretiva @submit.prevent impedirá que o formulário seja enviado normalmente e, portanto, chame o método createNewRoom().

Também usaremos o método createNewRoom() para acionar um evento chamado new_room usando EventBus.$emit('new_room', name);.

O primeiro parâmetro passado para o método $emit() é o nome do evento, enquanto o segundo parâmetro é o valor que queremos passar, que no nosso caso é o nome da sala. Vamos ouvir esse evento no componente Rooms que criaremos em seguida.

Componente Rooms

Usaremos o componente Rooms para listar as salas. Para adicionar o componente Rooms crie um novo arquivo chamado Rooms.vue na pasta src/components. Em seguida, adicione o seguinte código a ele:

<template>
   <div class="col-md-3 rooms">
       <div class="room" v-for="room in rooms" v-bind:key="room.id" @click="showRoom(room.name)">
           {{room.name}}
       </div>
   <AddRoom /> <!-- Imported AddRoom component -->
   </div>
</template>

<script>
import { EventBus } from '../Event'
import AddRoom from '../components/AddRoom'

export default {
 name: "Rooms", // Name of the component
 data() {
   return {
       rooms: [
           {id: 1, name: 'PHP Room'},
           {id: 2, name: 'Python Room'},
           {id: 3, name: 'Daily standup'}
       ],
       roomCount: 3, // used to keep track of the number of rooms present
       loading: false, // indicate when tracks in a room is being loaded
   }
 },
 components: {
   AddRoom // imported AddRoom component
 },
 created() {
 },
 methods: {
   showRoom(room) {
       EventBus.$emit('show_room', room);
   }
 }

}
</script>

<style scoped> /* scoped attribute is used here so the styling applies to this component alone */
   .rooms > .room {
       border: 1px solid rgb(124, 129, 124);
       padding: 13px;
       margin: 3px 0px;
       color: ghostwhite;
   }

   .rooms {
     border: 1px solid rgb(64, 68, 64);
     cursor: pointer;
   }
</style>

A diretiva v-for na tag <template> renderizará as salas. Além disso, usaremos a diretiva @click para ouvir os eventos de clique do usuário. Quando uma sala é clicada, vamos carregar o bate-papo para essa sala específica chamando o método showRoom().

Em seguida, usaremos o método showRoom() para acionar um evento - 'show_room'. Ao clicar em uma sala, chamaremos o método showRoom(), que será responsável por listar as faixas da sala específica.

Também temos algumas salas padrão, como visto no método data(), que foram codificadas para o app. Listaremos essas salas assim que o app for carregado.

Vamos ouvir o evento new_room. No componente AddRoom, há um formulário para adicionar uma nova sala. Assim que o formulário da sala for enviado, um evento new_room será acionado. Precisamos saber quando isso acontece neste componente (componente Rooms) para que possamos anexar a sala recentemente criada à lista de salas. Para isso, atualize o método created em src/components/Rooms.vue, que está em branco com o seguinte código:

 created() {
   EventBus.$on('new_room', (data) => {
       this.roomCount++;
       this.rooms.push({id: this.roomCount, name: data});
   });
 },

O método created() é um método Vue para execução de instruções assim que o Vue é carregado.

Componente Log

É bom ver as coisas à medida que elas acontecem. Adicionaremos logs de toda a ação que ocorre em uma sala, como quando um usuário entra em uma sala ou sai dela.

Crie um novo arquivo denominado Logs.vue na pasta src/components e adicione o seguinte código a ele:

<template>
    <div class="col-md-3 box">
        <div class="log"  v-for="log in logs" v-bind:key="log.id">
            {{log.message}}
        </div>
    </div>
</template>

<script>

import { EventBus } from '../Event'
import axios from 'axios'

export default {
  name: "Logs",
  data() {
    return {
        logs: [],
        logCount: 0
    }
  },
  created() {
    EventBus.$on('new_log', (message) => {
        this.logs.push( {id: this.logCount, message: message} );

        this.logCount += 1; 
    })
  },
}
</script>

<style scoped>
    .log {
        border: 1px solid rgb(124, 129, 124);
        padding: 13px;
        margin: 3px 0px;
        color: ghostwhite;
    }
</style>

Aqui, no método data(), definimos uma matriz para manter registros. Quando houver um novo registro, anexaremos o registro à matriz.

Em seguida, com a diretiva v-for, faremos um loop pela matriz de registros e exibiremos os registros para a visualização.

No método created(), estamos ouvindo ativamente um evento new_log. Quando houver um novo registro, anexaremos o registro à matriz de registros.

Componente Video

Usaremos este componente para exibir faixas locais e remotas. Quando um usuário clica em uma sala, iniciamos um bate-papo para essa sala e exibimos as faixas dos respectivos DOMs.

Crie um arquivo Video.vue em src/components e adicione o seguinte código a ele:

<template>
   <div class="col-md-6 box">
       <div class="roomTitle">
           <span v-if="loading"> Loading... {{roomName}}</span>
           <span v-else-if="!loading && roomName"> Connected to {{roomName}}</span>
           <span v-else>Select a room to get started</span>
       </div>
       <div class="row remote_video_container">
           <div id="remoteTrack"></div>
       </div>
       <div class="spacing"></div>
       <div class="row">
           <div id="localTrack"></div>
       </div>
   </div>
</template>

<script>
import { EventBus } from '../Event'
import Twilio, { connect, createLocalTracks, createLocalVideoTrack } from 'twilio-video'
import axios from 'axios'

export default {
 name: "Video",
 data() {
   return {
     loading: false,
     data: {},
     localTrack: false,
     remoteTrack: '',
     activeRoom: '',
     previewTracks: '',
     identity: '',
     roomName: null,
   }
 },
 props: ['username'], // props that will be passed to this component
 created() {},
 methods: {
   // Generate access token
   async getAccessToken() {},

   // Trigger log events 
   dispatchLog(message) {},

   // Attach the Tracks to the DOM.
   attachTracks(tracks, container) {},

    // Attach the Participant's Tracks to the DOM.
   attachParticipantTracks(participant, container) {},

   // Detach the Tracks from the DOM.
   detachTracks(tracks) {},

   // Detach the Participant's Tracks from the DOM.
   detachParticipantTracks(participant) {},

   // Leave Room.
   leaveRoomIfJoined() {},

   // Create a new chat
   createChat(room_name) {},
   }
}
</script>

<style >
   .remote_video_container {
     left: 0;
     margin: 0;
     border: 1px solid rgb(124, 129, 124);
   }
   #localTrack video {
       border: 3px solid rgb(124, 129, 124);
       margin: 0px;
       max-width: 50% !important;
       background-repeat: no-repeat;
   }
   .spacing {
     padding: 20px;
     width: 100%;
   }
   .roomTitle {
       border: 1px solid rgb(124, 129, 124);
       padding: 4px;
       color: dodgerblue;
   }
</style>

Na tag <template>, temos algumas condições que verificam se estamos carregando um bate-papo. Assim, se iniciarmos um bate-papo, exibiremos Loading... {{roomName}} (Carregando... {{nome da sala}}). Se não estiver carregando um bate-papo e roomName estiver definido, será exibido Connected to {{roomName}} (Conectado a {{Nome da sala}}). Caso contrário, exibiremos Select a room to get started (Selecione uma sala para começar).

No método data(), iniciamos algumas variáveis que usaremos em breve.

Também importamos o pacote Twilio JavaScript para esse componente, o que facilita a interação com a Twilio.

Além disso, no bloco Methods (Métodos), há algumas funções em branco que definimos lá. Adicionaremos seus respectivos códigos passo a passo à medida que avançarmos neste tutorial.

Agora que temos todos os componentes, A página agora deve ter a seguinte aparência:

Tela do projeto em funcionamento com um campo de texto e um botão &#x27;Enviar&#x27; (submit).

Quando você insere um nome de usuário e envia:

Tela do projeto em funcionamento com os elementos que aparecem após o usuário clicar em &#x27;Enviar&#x27; da imagem anterior.

Iniciar o bate-papo

Para iniciar um bate-papo, precisamos de um token. Vamos adicionar uma função para gerar esses tokens de acesso. Adicione o código abaixo ao bloco getAccessToken() em src/components/Video.vue:


async getAccessToken() {
  return await axios.get(`http://localhost:3000/token?identity=${this.username}`);
},

 http://localhost:3000/ é o endereço do servidor Node.js que criamos anteriormente.

Aqui, estamos nos conectando ao nosso servidor Node.js para gerar um token.

this.username é passado como um incremento para o componente Video. Pediremos a um usuário que forneça um nome de usuário antes que ele possa acessar o bate-papo. Em seguida, usaremos esse nome de usuário para identificar exclusivamente cada usuário usando nosso aplicativo. Vamos implementar isso em breve.

Em seguida, adicione uma função para acionar eventos de registro. Adicione o código abaixo à função dispatchLog(message) em src/components/Video.vue:

// Trigger log events 
   dispatchLog(message) {
       EventBus.$emit('new_log', message);
   },

Em seguida, adicione uma função para conectar a faixa ao DOM. Adicione o código abaixo à função attachTracks(tracks, container) em src/components/Video.vue:

 // Attach the Tracks to the DOM.
   attachTracks(tracks, container) {
       tracks.forEach(function(track) {
           container.appendChild(track.attach());
       });
   },

Em seguida, adicione uma função para anexar as faixas do participante ao DOM. Adicione o código abaixo ao bloco de função attachParticipantTracks(participant, container) em src/components/Video.vue:

   // Attach the Participant's Tracks to the DOM.
   attachParticipantTracks(participant, container) {
       let tracks = Array.from(participant.tracks.values());
       this.attachTracks(tracks, container);
   },

Em seguida, adicione uma função para remover as faixas conectadas do DOM. Adicione o código abaixo ao bloco methods: { } em src/components/Video.vue:

// ...

<script>
import { EventBus } from '../Event'
import Twilio, { connect, createLocalTracks, createLocalVideoTrack } from 'twilio-video'
import axios from 'axios'

export default {
name: "Video",
data() {
  return {
    loading: false,
    data: {},
    localTrack: false,
    remoteTrack: '',
    activeRoom: '',
    previewTracks: '',
    identity: '',
    roomName: null,
  }
},
props: ['username'], // props that will be passed to this component
created() {},
 methods: {
     async getAccessToken() {
       return await axios.get(`http://localhost:3000/token?identity=${this.username}`);
     },
     // Trigger log events
   dispatchLog(message) {
       EventBus.$emit('new_log', message);
   },
    // Attach the Tracks to the DOM.
  attachTracks(tracks, container) {
      tracks.forEach(function(track) {
          container.appendChild(track.attach());
      });
  },
     // Attach the Participant's Tracks to the DOM.
  attachParticipantTracks(participant, container) {
      let tracks = Array.from(participant.tracks.values());
      this.attachTracks(tracks, container);
  },
     // Detach the Tracks from the DOM.
  detachTracks(tracks) {
      tracks.forEach( (track) => {
          track.detach().forEach((detachedElement) => {
             detachedElement.remove();
          });
      });
  },
 }
}
</script>

Em seguida, adicione uma função para remover as faixas do participante conectado do DOM. Adicione o código abaixo ao bloco de função detachParticipantTracks(participant) em src/components/Video.vue:

   // Detach the Participant's Tracks from the DOM.
   detachParticipantTracks(participant) {
       let tracks = Array.from(participant.tracks.values());
       this.detachTracks(tracks);
   },

Por fim, adicione uma função para sair de uma sala na qual um usuário entrou. Adicione o código abaixo ao bloco de função leaveRoomIfJoined() em src/components/Video.vue:

   // Leave Room.
   leaveRoomIfJoined() {
       if (this.activeRoom) {
           this.activeRoom.disconnect();
       }
   },

Vamos criar uma função para criar uma sala de bate-papo. Adicione o seguinte ao bloco de função createChat(room_name) de src/components/Video.vue:


  createChat(room_name) {
      this.loading = true;
      const VueThis = this;

      this.getAccessToken().then( (data) => {
          VueThis.roomName = null;
          const token = data.data.token;
          let connectOptions = {
              name: room_name,
              // logLevel: 'debug',
              audio: true,
              video: { width: 400 }
          };
          // before a user enters a new room,
          // disconnect the user from they joined already
          this.leaveRoomIfJoined();
        
          // remove any remote track when joining a new room
          document.getElementById('remoteTrack').innerHTML = "";

          Twilio.connect(token, connectOptions).then(function(room) {
              // console.log('Successfully joined a Room: ', room);
              VueThis.dispatchLog('Successfully joined a Room: '+ room_name);

              // set active toom
              VueThis.activeRoom = room;
              VueThis.roomName = room_name;
              VueThis.loading = false;

              // Attach the Tracks of all the remote Participants.

              // When a Participant joins the Room, log the event.

              // When a Participant adds a Track, attach it to the DOM.

              // When a Participant removes a Track, detach it from the DOM.

              // When a Participant leaves the Room, detach its Tracks.

              // if local preview is not active, create it

         });
      })
   },

No código anterior:

  • This.getAccessToken() buscará o token de acesso para um usuário do servidor Node.js que criamos anteriormente.
  • connectOptions é uma variável que contém a opção para criar um novo bate-papo na Twilio. Aqui passamos o nome da sala, a largura do quadro do vídeo, etc.
  • Em seguida, chamamos o método Twilio.connect, que criará a sala que requer um token.

Em seguida, vamos anexar todos os módulos de todos os participantes que já estão na sala antes de um usuário entrar.

Adicione o seguinte código ao método Twilio.connect no arquivo src/components/Video.vue logo após o comentário // Attach the Tracks of all the remote Participants (Anexar as trilhas de todos os participantes remotos).


              room.participants.forEach(function(participant) {
                  let previewContainer = document.getElementById('remoteTrack');
                  VueThis.attachParticipantTracks(participant, previewContainer);
              });

Em seguida, registre um evento quando um usuário entrar em uma sala. Adicione o seguinte código ao bloco de método Twilio.connect no arquivo src/components/Video.vue logo abaixo do comentário // When a Participant joins the Room, log the event (Quando um participante entra na sala, registre o evento).:

                        room.on('participantConnected', function(participant) {
                              VueThis.dispatchLog("Joining: '" + participant.identity + "'");
                       });

Em seguida, adicione faixas ao DOM assim que um usuário anexar uma nova faixa. Adicione o seguinte código ao bloco de método Twilio.connect no arquivo src/components/Video.vue logo abaixo do comentário // When a Participant adds a Track, attach it to the DOM (Quando um participante adiciona uma trilha, anexe no DOM).:

               room.on('trackAdded', function(track, participant) {
                   VueThis.dispatchLog(participant.identity + " added track: " + track.kind);
                   let previewContainer = document.getElementById('remoteTrack');
                   VueThis.attachTracks([track], previewContainer);
               });

Quando um participante remove uma faixa, precisamos removê-la do DOM. Adicione o seguinte código ao bloco de método Twilio.connect no arquivo src/components/Video.vue logo abaixo do comentário // When a Participant removes a Track, detach it to the DOM (Quando um participante remove uma trilha, retire do DOM).:

               room.on('trackRemoved', function(track, participant) {
                   VueThis.dispatchLog(participant.identity + " removed track: " + track.kind);
                   VueThis.detachTracks([track]);
               });

Em seguida, vamos remover as faixas de um participante do DOM assim que ele sair do bate-papo. Adicione o seguinte código ao método Twilio-connect no arquivo src/components/Video.vue logo abaixo de // When a Participant leaves the Room, detach its Tracks. (Quando um participante deixa a sala, retire as trilhas.):

               room.on('participantDisconnected', function(participant) {
                   VueThis.dispatchLog("Participant '" + participant.identity + "' left the room");
                   VueThis.detachParticipantTracks(participant);
               });

Às vezes, antes de entrar em uma sala, você quer ver como você está. Vamos exibir uma faixa local para o DOM.

Por fim, adicione o seguinte código ao bloco de método Twilio.connect no arquivo src/components/Video.vue abaixo do comentário // if local preview is not active, create it (Se a visualização local não estiver ativa, crie a mesma):

              if(!VueThis.localTrack) {

                  createLocalVideoTrack().then(track => {
                    let localMediaContainer = document.getElementById('localTrack');

                    localMediaContainer.appendChild(track.attach());
                    VueThis.localTrack = true;
                  });
              }

Se você acompanhou de perto, seu arquivo Video.vue deve se parecer com este.

Assim que o Vue for iniciado, começaremos a ouvir eventos de quando um usuário quiser entrar em uma nova sala.
Para fazer isso, adicione o seguinte código ao bloco de método created() do componente src/components/Video.vue:

// ...
     EventBus.$on('show_room', (room_name) => {
         this.createChat(room_name);
     })

   // When a user is about to transition away from this page, 
   // disconnect from the room, if joined.
   window.addEventListener('beforeunload', this.leaveRoomIfJoined);

// ...

Agora, quando houver um evento show_room, chamaremos a função que acabamos de criar acima - createChat, para criar um bate-papo para essa sala.

Conclusão

Muito bem! Para testar o que você criou, carregue o aplicativo em guias diferentes do navegador, preencha o nome de usuário e clique em qualquer sala para começar a conversar. 

GIF com animação da tela do projeto em funcionamento e carregando os vídeos.

Neste tutorial, você viu como adicionar chat por vídeo ao aplicativo Vue.js usando a tecnologia de bate-papo Twilio Programmable Video.

Mais uma coisa. Usamos um meio simples para obter um nome de usuário para aqueles que usam o aplicativo, mas esse método não é muito seguro. Se o que você está criando não deve ser publicamente acessível, você deve considerar um meio de autenticar seus usuários, para que somente os usuários em que você confia possam usar o app. Consulte https://www.twilio.com/docs/authy para saber como autenticar usuários. Você também pode obter o app completo em Github.

Este artigo foi traduzido do original "Build a Video Chat App with JavaScript, Vue.js and Programmable Video". Enquanto melhoramos nossos processos de tradução, adoraríamos receber seus comentários em help@twilio.com - contribuições valiosas podem render brindes da Twilio.