Building a WebRTC web app with VueJS

Blog post ApiRTC VueJS

Building a WebRTC web app with VueJS

Last Updated on June 29, 2021

We have observed a growing demand for integrating WebRTC in modern frameworks for building web applications. We have packaged ApiRTC javascript API to make it easier to use from any of the most used modern frameworks. In this post we will demonstrate a simple web application developed using VueJS and ApiRTC.

 

How does ApiRTC work?

 

The first goal of ApiRTC is to enable fast development of real-time communication applications using WebRTC. WebRTC, supports video, voice, and generic data to be sent between peers without signaling server, but it doesn’t know how to discover peers. ApiRTC handles all the network services a WebRTC application requires for you.

 

signalisation ApiRTC

Also WebRTC can be slightly differently implemented by the different navigators. ApiRTC comes as an interoperability layer to handle cross platform real-time communication.

 

Interoperability ApiRTC

 

So don’t mind about the signaling, or the different browsers: ApiRTC lets you focus on the web app development.

 

A simple WebRTC application

 

Let’s build a light WebRTC application to video chat with two or more participants using VueJS like in this example.

 

 

ApiRTC WebRTC VueJS

 

 

Step-by-step tutorial with VueJS and ApiRTC

 

Install VueJS command line interface

 

sudo npm install -g @vue/cli

 

Create the new vue app

 

vue create apirtc-vuejs

 

Note: We have used Vue3 mode for this demo

 

cd apirtc-vuejs

 

Import ApiRTC

 

npm install @apizee/apirtc@latest --save

 

Code the application

 

  • Remove src/components/HelloWorld.vue
  • Create a component called Conversation in a new file src/components/Conversation.vue:

 

<template>
  <div>
    <form v-if="!conversation" @submit.prevent="getOrcreateConversation">
      <input type="text" placeholder="abcd" v-model="name" />&nbsp;
      <button type="submit" title="Get Or Create Conversation">
        GetOrCreateConversation
      </button>
    </form>
    <div v-show="conversation">
      <p>{{ name }}</p>
      <div id="remote-container"></div>
      <div id="local-container"></div>
    </div>
  </div>
</template>

<script>

import { UserAgent } from "@apizee/apirtc";

export default {
  name: "Conversation",
  props: {},
  methods: {
    getOrcreateConversation() {
      console.log("getOrcreateConversation called");
      // TODO
    },
  },
  data() {
    return {
      name: "",
      conversation: null,
    };
  },
};
</script>

 

 

In src/App.vue, remove references to HelloWorld component, replacing it by Conversation component:

 

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <Conversation />
</template>

<script>
import Conversation from "./components/Conversation.vue";

export default {
  name: "App",
  components: {
    Conversation,
  },
};
</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;
}
</style>

 

  • Finally, in src/components/Conversation.vue implement the getOrcreateConversation() method:

 

getOrcreateConversation() {
      console.log("getOrcreateConversation called");

      var localStream = null;

      //==============================
      // 1/ CREATE USER AGENT
      //==============================
      var ua = new UserAgent({
        uri: "apzkey:myDemoApiKey",
      });

      //==============================
      // 2/ REGISTER
      //==============================
      ua.register().then((session) => {
        //==============================
        // 3/ CREATE CONVERSATION
        //==============================
        const conversation = session.getConversation(this.name);
        this.conversation = conversation;

        //==========================================================
        // 4/ ADD EVENT LISTENER : WHEN NEW STREAM IS AVAILABLE IN CONVERSATION
        //==========================================================
        conversation.on("streamListChanged", (streamInfo) => {
          console.log("streamListChanged :", streamInfo);
          if (streamInfo.listEventType === "added") {
            if (streamInfo.isRemote === true) {
              conversation
                .subscribeToMedia(streamInfo.streamId)
                .then((stream) => {
                  console.log("subscribeToMedia success", stream);
                })
                .catch((err) => {
                  console.error("subscribeToMedia error", err);
                });
            }
          }
        });
        //=====================================================
        // 4 BIS/ ADD EVENT LISTENER : WHEN STREAM IS ADDED/REMOVED TO/FROM THE CONVERSATION
        //=====================================================
        conversation
          .on("streamAdded", (stream) => {
            stream.addInDiv(
              "remote-container",
              "remote-media-" + stream.streamId,
              {},
              false
            );
          })
          .on("streamRemoved", (stream) => {
            stream.removeFromDiv(
              "remote-container",
              "remote-media-" + stream.streamId
            );
          });

        //==============================
        // 5/ CREATE LOCAL STREAM
        //==============================
        ua.createStream({
          constraints: {
            audio: true,
            video: true,
          },
        })
          .then((stream) => {
            console.log("createStream :", stream);

            // Save local stream
            localStream = stream;
            stream.removeFromDiv("local-container", "local-media");
            stream.addInDiv("local-container", "local-media", {}, true);

            //==============================
            // 6/ JOIN CONVERSATION
            //==============================
            conversation
              .join()
              .then((response) => {
                console.log("Conversation joined", response);
                //==============================
                // 7/ PUBLISH LOCAL STREAM
                //==============================
                conversation
                  .publish(localStream)
                  .then((stream) => {
                    console.log("published", stream);
                  })
                  .catch((err) => {
                    console.error("publish error", err);
                  });
              })
              .catch((err) => {
                console.error("Conversation join error", err);
              });
          })
          .catch((err) => {
            console.error("create stream error", err);
          });
      });
    }

 

 

Run!

 

Run npm run serve for a dev server. Navigate to http://localhost:8080/.

 

The application can be opened in multiple tabs to test an ApiRTC conversation with multiple peers.

 

You can find this tutorial reference on our github.

 

What’s next?

 

You have probably noticed that our sample webapp is using a myDemoApiKey to access ApiRTC services when instantiating the UserAgent:

 

var ua = new UserAgent({
      uri: 'apzkey:myDemoApiKey'
    });

 

In order to go forward with your own application, you will soon require your own apiKey to isolate your conversations from demo users, and benefit from all features ApiRTC can offer.

 

You can get your apiKey for free. When you have one, just replace myDemoApiKey by yours:

 

var ua = new UserAgent({
      uri: 'apzkey:<YOUR_API_KEY>'
    });

 

Thank you so much for joining the ApiRTC community. Until the next time, go build great apps!