From a21fb76ac019b2fdd885824957e0956a8aa0d88b Mon Sep 17 00:00:00 2001 From: voluntas <nakai@shiguredo.jp> Date: Thu, 29 Feb 2024 13:51:53 +0900 Subject: [PATCH] =?UTF-8?q?sendrecv=20=E3=82=92=20class=20=E5=8C=96?= =?UTF-8?q?=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/sendrecv/index.html | 10 +-- examples/sendrecv/main.mjs | 108 -------------------------- examples/sendrecv/main.mts | 142 +++++++++++++++++++++++++++++++++++ tests/sendrecv.spec.ts | 8 +- 4 files changed, 151 insertions(+), 117 deletions(-) delete mode 100644 examples/sendrecv/main.mjs create mode 100644 examples/sendrecv/main.mts diff --git a/examples/sendrecv/index.html b/examples/sendrecv/index.html index 17411a81..e6ea1050 100644 --- a/examples/sendrecv/index.html +++ b/examples/sendrecv/index.html @@ -11,8 +11,8 @@ <h1>Sendrecv test</h1> <div style="display: flex;"> <div> <h2>sendrecv1</h2> - <button id="start-sendrecv1">start</button> - <button id="stop-sendrecv1">stop</button><br /> + <button id="sendrecv1-start">start</button> + <button id="sendrecv1-stop">stop</button><br /> <video id="sendrecv1-local-video" autoplay="" playsinline="" controls="" style="width: 320px; height: 240px; border: 1px solid black;"></video> <div id="sendrecv1-connection-id"></div> @@ -20,8 +20,8 @@ <h2>sendrecv1</h2> </div> <div> <h2>sendrecv2</h2> - <button id="start-sendrecv2">start</button> - <button id="stop-sendrecv2">stop</button><br /> + <button id="sendrecv2-start">start</button> + <button id="sendrecv2-stop">stop</button><br /> <video id="sendrecv2-local-video" autoplay="" playsinline="" controls="" style="width: 320px; height: 240px; border: 1px solid black;"></video> <div id="sendrecv2-connection-id"></div> @@ -30,7 +30,7 @@ <h2>sendrecv2</h2> </div> </div> - <script type="module" src="./main.mjs"></script> + <script type="module" src="./main.mts"></script> </body> </html> \ No newline at end of file diff --git a/examples/sendrecv/main.mjs b/examples/sendrecv/main.mjs deleted file mode 100644 index 8f51e842..00000000 --- a/examples/sendrecv/main.mjs +++ /dev/null @@ -1,108 +0,0 @@ -import Sora from '../../dist/sora.mjs' - -const SORA_SIGNALING_URL = import.meta.env.VITE_SORA_SIGNALING_URL -const SORA_CHANNEL_ID_PREFIX = import.meta.env.VITE_SORA_CHANNEL_ID_PREFIX || '' -const SORA_CHANNEL_ID_SUFFIX = import.meta.env.VITE_SORA_CHANNEL_ID_SUFFIX || '' -const ACCESS_TOKEN = import.meta.env.VITE_ACCESS_TOKEN || '' - -const channelId = `${SORA_CHANNEL_ID_PREFIX}sendrecv${SORA_CHANNEL_ID_SUFFIX}` -const debug = false -const sora = Sora.connection(SORA_SIGNALING_URL, debug) -const metadata = { access_token: ACCESS_TOKEN } -const options = {} - -const sendrecv1 = sora.sendrecv(channelId, metadata, options) - -sendrecv1.on('notify', (event) => { - if (event.event_type === 'connection.created' && sendrecv1.connectionId === event.connection_id) { - const connectionIdElement = document.querySelector('#sendrecv1-connection-id') - connectionIdElement.textContent = event.connection_id - } -}) - -sendrecv1.on('track', (event) => { - const stream = event.streams[0] - if (!stream) return - const remoteVideoId = `sendrecv1-remotevideo-${stream.id}` - const remoteVideos = document.querySelector('#sendrecv1-remote-videos') - if (!remoteVideos.querySelector(`#${remoteVideoId}`)) { - const remoteVideo = document.createElement('video') - remoteVideo.id = remoteVideoId - remoteVideo.style.border = '1px solid red' - remoteVideo.autoplay = true - remoteVideo.playsinline = true - remoteVideo.controls = true - remoteVideo.width = '160' - remoteVideo.height = '120' - remoteVideo.srcObject = stream - remoteVideos.appendChild(remoteVideo) - } -}) - -sendrecv1.on('removetrack', (event) => { - const remoteVideo = document.querySelector(`#sendrecv1-remotevideo-${event.target.id}`) - if (remoteVideo) { - document.querySelector('#sendrecv1-remote-videos').removeChild(remoteVideo) - } -}) - -const sendrecv2 = sora.sendrecv(channelId, metadata, options) - -sendrecv2.on('notify', (event) => { - if (event.event_type === 'connection.created' && sendrecv2.connectionId === event.connection_id) { - const connectionIdElement = document.querySelector('#sendrecv2-connection-id') - connectionIdElement.textContent = event.connection_id - } -}) - -sendrecv2.on('track', (event) => { - const stream = event.streams[0] - if (!stream) return - const remoteVideoId = `sendrecv2-remotevideo-${stream.id}` - const remoteVideos = document.querySelector('#sendrecv2-remote-videos') - if (!remoteVideos.querySelector(`#${remoteVideoId}`)) { - const remoteVideo = document.createElement('video') - remoteVideo.id = remoteVideoId - remoteVideo.style.border = '1px solid red' - remoteVideo.autoplay = true - remoteVideo.playsinline = true - remoteVideo.controls = true - remoteVideo.width = '160' - remoteVideo.height = '120' - remoteVideo.srcObject = stream - remoteVideos.appendChild(remoteVideo) - } -}) - -sendrecv2.on('removetrack', (event) => { - const remoteVideo = document.querySelector(`#sendrecv2-remotevideo-${event.target.id}`) - if (remoteVideo) { - document.querySelector('#sendrecv2-remote-videos').removeChild(remoteVideo) - } -}) - -document.querySelector('#start-sendrecv1').addEventListener('click', async () => { - // sendrecv1 - const mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true }) - await sendrecv1.connect(mediaStream) - document.querySelector('#sendrecv1-local-video').srcObject = mediaStream -}) - -document.querySelector('#start-sendrecv2').addEventListener('click', async () => { - // sendrecv2 - const mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true }) - await sendrecv2.connect(mediaStream) - document.querySelector('#sendrecv2-local-video').srcObject = mediaStream -}) - -document.querySelector('#stop-sendrecv1').addEventListener('click', async () => { - await sendrecv1.disconnect() - document.querySelector('#sendrecv1-local-video').srcObject = null - document.querySelector('#sendrecv1-remote-videos').innerHTML = null -}) - -document.querySelector('#stop-sendrecv2').addEventListener('click', async () => { - await sendrecv2.disconnect() - document.querySelector('#sendrecv2-local-video').srcObject = null - document.querySelector('#sendrecv2-remote-videos').innerHTML = null -}) diff --git a/examples/sendrecv/main.mts b/examples/sendrecv/main.mts new file mode 100644 index 00000000..4b54bf74 --- /dev/null +++ b/examples/sendrecv/main.mts @@ -0,0 +1,142 @@ +import Sora, { + type SoraConnection, + type SignalingNotifyMessage, + ConnectionPublisher, +} from '../../dist/sora' + +document.addEventListener('DOMContentLoaded', async () => { + const SORA_SIGNALING_URL = import.meta.env.VITE_SORA_SIGNALING_URL + const SORA_CHANNEL_ID_PREFIX = import.meta.env.VITE_SORA_CHANNEL_ID_PREFIX || '' + const SORA_CHANNEL_ID_SUFFIX = import.meta.env.VITE_SORA_CHANNEL_ID_SUFFIX || '' + const ACCESS_TOKEN = import.meta.env.VITE_ACCESS_TOKEN || '' + + const sendrecv1 = new SoraClient( + 'sendrecv1', + SORA_SIGNALING_URL, + SORA_CHANNEL_ID_PREFIX, + SORA_CHANNEL_ID_SUFFIX, + ACCESS_TOKEN, + ) + + const sendrecv2 = new SoraClient( + 'sendrecv2', + SORA_SIGNALING_URL, + SORA_CHANNEL_ID_PREFIX, + SORA_CHANNEL_ID_SUFFIX, + ACCESS_TOKEN, + ) + + document.querySelector('#sendrecv1-start')?.addEventListener('click', async () => { + // sendrecv1 + const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true }) + await sendrecv1.connect(stream) + }) + document.querySelector('#sendrecv1-stop')?.addEventListener('click', async () => { + await sendrecv1.disconnect() + }) + + document.querySelector('#sendrecv2-start')?.addEventListener('click', async () => { + // sendrecv2 + const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true }) + await sendrecv2.connect(stream) + }) + document.querySelector('#sendrecv2-stop')?.addEventListener('click', async () => { + await sendrecv2.disconnect() + }) +}) + +class SoraClient { + // sendrecv1 or sendrecv2 + private label: string + + private debug = false + + private channelId: string + private metadata: { access_token: string } + private options: object + + private sora: SoraConnection + private connection: ConnectionPublisher + + constructor( + label: string, + signalingUrl: string, + channelIdPrefix: string, + channelIdSuffix: string, + accessToken: string, + ) { + this.label = label + + this.sora = Sora.connection(signalingUrl, this.debug) + this.channelId = `${channelIdPrefix}sendrecv${channelIdSuffix}` + this.metadata = { access_token: accessToken } + this.options = {} + + this.connection = this.sora.sendrecv(this.channelId, this.metadata, this.options) + + this.connection.on('notify', this.onnotify.bind(this)) + this.connection.on('track', this.ontrack.bind(this)) + this.connection.on('removetrack', this.onremovetrack.bind(this)) + } + + async connect(stream: MediaStream) { + await this.connection.connect(stream) + const localVideo = document.querySelector<HTMLVideoElement>(`#${this.label}-local-video`) + if (localVideo) { + localVideo.srcObject = stream + } + } + + async disconnect() { + await this.connection.disconnect() + + // お掃除 + const localVideo = document.querySelector<HTMLVideoElement>(`#${this.label}-local-video`) + if (localVideo) { + localVideo.srcObject = null + } + // お掃除 + const remoteVideos = document.querySelector(`#${this.label}-remote-videos`) + if (remoteVideos) { + remoteVideos.innerHTML = '' + } + } + + private onnotify(event: SignalingNotifyMessage): void { + if ( + event.event_type === 'connection.created' && + this.connection.connectionId === event.connection_id + ) { + const connectionIdElement = document.querySelector(`#${this.label}-connection-id`) + if (connectionIdElement) { + connectionIdElement.textContent = event.connection_id + } + } + } + + private ontrack(event: RTCTrackEvent): void { + const stream = event.streams[0] + const remoteVideoId = `${this.label}-remotevideo-${stream.id}` + const remoteVideos = document.querySelector(`#${this.label}-remote-videos`) + if (remoteVideos && !remoteVideos.querySelector(`#${remoteVideoId}`)) { + const remoteVideo = document.createElement('video') + remoteVideo.id = remoteVideoId + remoteVideo.style.border = '1px solid red' + remoteVideo.autoplay = true + remoteVideo.playsInline = true + remoteVideo.controls = true + remoteVideo.width = 160 + remoteVideo.height = 120 + remoteVideo.srcObject = stream + remoteVideos.appendChild(remoteVideo) + } + } + + private onremovetrack(event: MediaStreamTrackEvent): void { + const target = event.target as MediaStream + const remoteVideo = document.querySelector(`#${this.label}-remotevideo-${target.id}`) + if (remoteVideo) { + document.querySelector(`#${this.label}-remote-videos`)?.removeChild(remoteVideo) + } + } +} diff --git a/tests/sendrecv.spec.ts b/tests/sendrecv.spec.ts index 1116ebd3..d8e62447 100644 --- a/tests/sendrecv.spec.ts +++ b/tests/sendrecv.spec.ts @@ -3,8 +3,8 @@ import { test } from '@playwright/test' test('sendrecv x2', async ({ page }) => { await page.goto('http://localhost:9000/sendrecv/') - await page.click('#start-sendrecv1') - await page.click('#start-sendrecv2') + await page.click('#sendrecv1-start') + await page.click('#sendrecv2-start') // #sendrecv1-connection-id 要素が存在し、その内容が空でないことを確認するまで待つ await page.waitForSelector('#sendrecv1-connection-id:not(:empty)') @@ -20,6 +20,6 @@ test('sendrecv x2', async ({ page }) => { const sendrecv2ConnectionId = await page.$eval('#sendrecv2-connection-id', (el) => el.textContent) console.log(`sendrecv2 connectionId=${sendrecv2ConnectionId}`) - await page.click('#stop-sendrecv1') - await page.click('#stop-sendrecv2') + await page.click('#sendrecv1-stop') + await page.click('#sendrecv2-stop') })