はじめに
vue.jsでズーム、グーグルミーツなどみたいオンライン会議サービスのアプリを作りましょう。
目的
シンプルなオンライン会議システムを開発
概要
システム方式・構成
システム構成は以下となります
- ウェブアプリケーション
vue.jsでウェブアプリケーション、ウェブカメラのストリーム、ローカルとリモートの画面 - SkyWay API サーバー
既存の外部NTTのSkyWay API
レシピ
まずは新skywayのコンソルからアカウントを作りましょう
https://console.skyway.ntt.com/signup/
メールを認証し、ログインするとプロジェクトを作成しましょう
名の例:kaigi
上からアプリケーションを作りましょう
アプリケーション名: kaigi
作成
アプリケーションIDとシークレットキーをコピーしておきます。
プロジェクトのフォルダーを作ります。
そのフォルダーからターミナル(コマンドプロンプト)を開きます。
以下のコマンドを実行します;
npm create vite
project name: kaigi
type: vue
language: javascript
cd kaigi
npm install
code .
Visual Studio コードを開始するはずです
VSコードのメニューからターミナルを開きましょう
npm i @skyway-sdk/room
npm i uuidv4
.env.localファイルを作ってアプリケーションIDとシークレットを以下通り入ります
VITE_SKYWAY_SECRET_KEY=シークレットキーを貼付
VITE_SKYWAY_APP_ID=アプリケーションIDを貼付
大事な情報ですので、公開しないようにしましょう。viteなら基準で*.localはgitから抜きます。
しかし、現在アプリはサーバーバックエンドを開発しませんので、ブラウザでシークレットキーをアクセスになってしまうので、必ずそのまま公開しないようにしましょう。
新しいvscodeのターミナルを開きしましょう
npm run dev
ローカルサーバーを開始ます。
アドレスをコピーしてブラウザに張り付けます
私場合は以下のアドレスが出ました:
http://localhost:5173/
app.vueを開いて以下通りに変更します
<script setup>
import StreamReceiver from './components/StreamReceiver.vue'
</script>
<template>
<StreamReceiver />
</template>
StreamReceiverのコンポーネント(アプリの部分)を呼びますということです
HelloWorld.vueを削除しましょう
同じところでcomponentsの中StreamReceiver.vueを作りましょう
<script setup>
import { ref } from 'vue'
import { SkyWayContext } from '@skyway-sdk/room';
// 現在のURL
const baseUrl = window.location.href.split('?')[0];
// div ref="stream-area"参考
const StreamArea = ref(null);
// 会議部屋を作ったかどうか
const RoomCreated = ref(false);
// ルームのIDの保管、シェアため
const RoomId = ref(null);
</script>
<template>
<h1>Kaigi</h1>
<div class="card">
<div ref="StreamArea" v-if="RoomCreated">
</div>
<div v-else>
<button @click="createRoom">Create Room</button>
</div>
<div v-if="RoomId">
<p>以下のURLは相手とシェア:</p>
<p>{{ baseUrl }}?room={{ RoomId }}</p>
<p>またはルームIDを送りましょう:</p>
<p>{{ RoomId }}</p>
<p>会議を開始するため以下のボタンをクリックしてください:</p>
<button @click="joinRoom">Join Room</button>
</div>
</div>
</template>
Create roomを押しても何も変わらない、まだ関数を作りませんでした。今度変更します。
その前はSkyWayAPIと繋がるためにTokenのコードを作らなければなりませんので
componentsのフォルダーの中SkywayToken.jsを作りましょう。
以下通り:
import { SkyWayAuthToken } from '@skyway-sdk/token';
import { uuidV4, nowInSec } from '@skyway-sdk/room';
export default function GetToken(app_id, secret) {
return new SkyWayAuthToken({
jti: uuidV4(),
iat: nowInSec(),
exp: nowInSec() + 60 * 60 * 24,
scope: {
app: {
id: app_id,
turn: true,
actions: ['read'],
channels: [
{
id: '*',
name: '*',
actions: ['write'],
members: [
{
id: '*',
name: '*',
actions: ['write'],
publication: {
actions: ['write'],
},
subscription: {
actions: ['write'],
},
},
],
sfuBots: [
{
actions: ['write'],
forwardings: [
{
actions: ['write'],
},
],
},
],
},
],
},
},
}).encode(secret);
}
そちらはアプリケーションIDやシークレットや設定を用いてトークンを作ってリターンします。
StreamReceiver.vueを変更しましょう
<script setup>
import { ref, onMounted } from 'vue'
import { SkyWayContext, SkyWayRoom, SkyWayStreamFactory, uuidV4 } from '@skyway-sdk/room';
import GetToken from './SkywayToken.js'
// SkyWayのトークンを作成する
const tokenString = GetToken(import.meta.env.VITE_SKYWAY_APP_ID, import.meta.env.VITE_SKYWAY_SECRET_KEY);
// SkyWayの実体とルームの実体を保管するため
const context = {'ctx': null, 'room': null};
// 現在のURL
const baseUrl = window.location.href.split('?')[0];
// div ref="stream-area"参考
const StreamArea = ref(null)
// 会議部屋を作ったかどうか
const RoomCreated = ref(false)
// ルームのIDの保管、シェアため
const RoomId = ref(null)
// SkyWayのAPIと繋がって実体を保管する
const getContext = async () => {
context.ctx = await SkyWayContext.Create(tokenString);
// トークンの更新
context.ctx.onTokenUpdateReminder.add(() => {
context.ctx.updateAuthToken(tokenString);
});
return context.ctx;
}
// 部屋を作り、ルームIDを保管する
const createRoom = async () => {
// ルームIDがない場合は作成する
if (!RoomId.value) {
RoomId.value = uuidV4();
}
// ルームの実体を作成する, p2pの手法
// FindOrCreateは同じ名前のルームがある場合はそれを使う
context.room = await SkyWayRoom.FindOrCreate(context.ctx, {
type: 'p2p',
name: RoomId.value,
});
// ルームを作ったことを示すため
RoomCreated.value = true
}
// 部屋に入る関数
const joinRoom = async () => {
if (!RoomId.value) {
alert ('No Room ID');
return;
}
// ルームの実体がない場合は作成する
if (!RoomCreated.value) {
await createRoom();
}
// ルームに入る, 今は名前はランダム、同じ名前だと入らないので、現在テストため
const member = await context.room.join({name: uuidV4()});
// Cameraのストリームを作成する
const videoStream = await SkyWayStreamFactory.createCameraVideoStream();
// 映像を送る
await member.publish(videoStream);
// ユーザーからCameraの映像を取得する
const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
// 映像を表示する
const video = document.createElement('video');
video.srcObject = stream;
video.autoplay = true;
video.playsInline = true;
video.muted = true;
video.style.width = '100%';
video.style.height = '100%';
StreamArea.value.appendChild(video);
// skywayのストリームへ添付する
skywayStream.attach(video);
// 映像を再生する
await video.play();
}
// ページが読み込まれたら SkyWayの実体を作成する
onMounted(async () => {
await getContext();
// URLでルームIDがある場合はそれを使う
RoomId.value = new URLSearchParams(window.location.search).get('room');
});
</script>
<template>
<h1>Kaigi</h1>
<div class="card">
<div ref="StreamArea" v-if="RoomCreated">
</div>
<div v-else>
<button @click="createRoom">Create Room</button>
</div>
<div v-if="RoomId">
<p>以下のURLは相手とシェア:</p>
<p>{{ baseUrl }}?room={{ RoomId }}</p>
<p>またはルームIDを送りましょう:</p>
<p>{{ RoomId }}</p>
<p>会議を開始するため以下のボタンをクリックしてください:</p>
<button @click="joinRoom">Join Room</button>
</div>
</div>
</template>
ブラウザを確認すると今create roomとjoin roomもできます。カメラストリームを開始はずです。
今度は相手も参加できるようにします。