Set up a LiveSwitch Vue Project
This tutorial demonstrates how to add video streaming to a Vue app using the LiveSwitch Web SDK.
Prerequisites
Before you begin, you must have done the following:
- Installed node.js and npm
- Added an application in the LiveSwitch Console and got the
Application ID
andShared Secret
for your application
Create a Vue App
Create a new Vue app using the Vue CLI.
Install the Vue CLI if you haven't done so.
npm install -g @vue/cli
In the terminal, find a location on your drive where you want to create the project and run the following command to create a Vue app named
my-app
. You can modify these presets as needed to suit your requirements.vue create --inlinePreset='{ "useConfigFiles": false, "plugins": { "@vue/cli-plugin-babel": {}, "@vue/cli-plugin-eslint": { "config": "base", "lintOn": ["save"] } }, "router": true, "routerHistoryMode": true }' my-app
Install the LiveSwitch Web SDK
To install the LiveSwitch Web SDK, do the following:
Go to the project directory.
cd my-app
Install the LiveSwitch Client SDK.
npm install fm.liveswitch
Create a LiveSwitch Vue Plugin
The best way to work with the asynchronous methods of the LiveSwitch SDK is to create a reusable bridge (plugin) between LiveSwitch and Vue. The following steps describe how to accomplish this:
Inside the
src
folder, create a new folder calledliveswitch
.Create a new file named
index.js
. In this file, import the LiveSwitch Web SDK to the project and create logic to stream video. For information about how to generate an authorization token, register a client to a channel and stream media, see Media Streaming Basics. The completed file should look like the following:import Vue from 'vue' import ls from 'fm.liveswitch' let instance export const getInstance = () => instance export const useLiveSwitch = ({ applicationId = '-specify-in-liveswitch_config.json', token = '', gatewayUrl = '-specify-in-liveswitch_config.json', // callback for when your local camera/mic are up and running onLocalMediaReady = function () {}, // callback for when a user joins onParticipantJoin = function () {}, // callback for when a user leaves onParticipantLeave = function () {} /// ...options }) => { if (instance) return instance // The 'instance' is simply a Vue object instance = new Vue({ data () { return { } }, methods: { async startStreaming () { const promise = new ls.Promise() try { this.client = new ls.Client(gatewayUrl, applicationId) this.connectionRecords = {} const channels = await this.client.register(token) // we auto-joined one channel, so just use that one this.channel = channels[0] // start local media - camera/microphone const media = new ls.LocalMedia(true, true) await media.start() onLocalMediaReady(media) // open a connection up to the server this.openUpstreamConnection(this.channel, media) // listen for other remote participants to open a connection this.channel.addOnRemoteUpstreamConnectionOpen((remoteConnectionInfo) => { this.addConnection(remoteConnectionInfo) }) // for connections that already exist when we joined, join them this.channel.getRemoteUpstreamConnectionInfos().forEach(remoteConnectionInfo => { this.addConnection(remoteConnectionInfo) }) promise.resolve(null) } catch (ex) { promise.reject(ex) } return promise }, openUpstreamConnection (channel, localMedia) { const audioStream = (localMedia.getAudioTrack() != null) ? new ls.AudioStream(localMedia) : null const videoStream = (localMedia.getVideoTrack() != null) ? new ls.VideoStream(localMedia) : null const connection = channel.createSfuUpstreamConnection(audioStream, videoStream) connection.addOnStateChange(conn => { if (conn.getState() === ls.ConnectionState.Failed) { this.openUpstreamConnection(channel, localMedia) } }) connection.open() return connection }, async stopStreaming () { const promise = new ls.Promise() try { await this.removeConnections() await this.client.unregister() promise.resolve(null) } catch (ex) { promise.reject(ex) } return promise }, async addConnection (info) { let promise = new ls.Promise() try { // create a remote media/view for the downstream const media = new ls.RemoteMedia() const video = new ls.VideoStream(null, media) // create the connection const connection = this.channel.createSfuDownstreamConnection(info, video) // store some metadata with the connection const record = { id: info.getClientId(), media: media, video: video, connection: connection } this.connectionRecords[connection.getId()] = record // hook up some events connection.addOnStateChange((c) => { switch (c.getState()) { case ls.ConnectionState.Connected: onParticipantJoin(record) break case ls.ConnectionState.Closed: case ls.ConnectionState.Failed: this.removeConnection(record) onParticipantLeave(record) break } }) // open the connection promise = connection.open() } catch (ex) { console.error(ex) promise.reject(ex) } return promise }, async removeConnections () { const promises = [] for (const [, record] of Object.entries(this.connectionRecords)) { promises.push(this.removeConnection(record)) } return Promise.all(promises) }, async removeConnection (record) { let promise = new ls.Promise() try { promise = record.connection.close() delete this.connectionRecords[record.connection.getId()] } catch (ex) { promise.reject(ex) } return promise } }, async created () { this.startStreaming() } }) return instance } export const LiveSwitchPlugin = { install (Vue, options) { Vue.prototype.$liveswitch = useLiveSwitch(options) } }
In the root directory of your app alongside your
package.json
file, create a new file calledliveswitch_config.json
.Add the following content and replace with your own Application ID and Shared Secret. If you use your own LiveSwitch Server, replace the Gateway URL. This information is used for generating an authorization token.
{ "applicationId": "replace-with-your-app-id", "gatewayUrl" : "https://cloud.liveswitch.io", "channelId": "/room/1", "sharedSecret": "replace-with-your-shared-secret" }
To render the video feeds, append the following to the
<style>
block inApp.vue
:video { width: auto !important; height: auto !important; position: relative !important; }
Note
For your production app, you should use the
LayoutManager
class. It dynamically manages the video elements to maximize the space on the page for video feeds.
Install and Use the Plugin
Finally, open src/main.js
and use Vue.use
to install the plugin. To do this, pass the following properties into the plugin:
- The token that was generated using the configuration file
- Three callbacks: one for your local camera, the other two for when a user joins or leaves
- Your Application ID
LiveSwitch imports the configuration file created earlier to initialize the plugin, and generate a token using that information. By taking this approach, your Shared Secret is never exposed to the outside world, and you can restrict access based on your requirements.
Update the
src/main.js
file with the following:import Vue from 'vue' import App from './App.vue' import router from './router' import ls from 'fm.liveswitch' // Import the LiveSwitch configuration import { applicationId, channelId, sharedSecret, gatewayUrl } from '../liveswitch_config.json' // Import the plugin import { LiveSwitchPlugin } from './liveswitch' Vue.config.productionTip = false // generate a token that will let us connect to the server // we use the values from the config here // Never generate tokens on the client side in a production application const token = ls.Token.generateClientRegisterToken(applicationId, null, null, null, null, [new ls.ChannelClaim(channelId)], sharedSecret) // a few handlers // in your production application, these handlers should // store the media/record objects in a reactive VueX store // where all your sub-components can access/react to them const onLocalMediaReady = function (media) { const home = document.getElementsByClassName('home')[0] home.insertBefore(media.getView(), home.firstChild) } const onParticipantJoin = function (record) { const home = document.getElementsByClassName('home')[0] home.insertBefore(record.media.getView(), home.firstChild) } const onParticipantLeave = function (record) { const home = document.getElementsByClassName('home')[0] home.removeChild(record.media.getView()) } // Install the LiveSwitch plugin Vue.use(LiveSwitchPlugin, { applicationId, token, gatewayUrl, onLocalMediaReady, onParticipantJoin, onParticipantLeave }) // normal vue stuff new Vue({ router, render: h => h(App) }).$mount('#app')
Run the app:
npm run serve
For the complete example app that this page describes, check out this GitHub repository.