diff --git a/examples/index.html b/examples/index.html index cf7a03da..7a11c2be 100644 --- a/examples/index.html +++ b/examples/index.html @@ -16,8 +16,6 @@
  • スポットライト視聴サンプル
  • サイマルキャスト配信/視聴サンプル
  • メッセージングサンプル
  • -
  • 送信音声ビットレートサンプル
  • -
  • 送信音声コーデックサンプル
  • 送信音声サンプル
  • diff --git a/examples/sendonly_audio_bit_rate/index.html b/examples/sendonly_audio_bit_rate/index.html deleted file mode 100644 index 505bb4d4..00000000 --- a/examples/sendonly_audio_bit_rate/index.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - Sendonly AudioBitRate test - - - -
    -

    Sendonly test

    - - -
    -
    - -
    - -
    -
    -
    - - - - \ No newline at end of file diff --git a/examples/sendonly_audio_bit_rate/main.mts b/examples/sendonly_audio_bit_rate/main.mts deleted file mode 100644 index a28dbf95..00000000 --- a/examples/sendonly_audio_bit_rate/main.mts +++ /dev/null @@ -1,128 +0,0 @@ -import Sora, { - type SignalingNotifyMessage, - type ConnectionPublisher, - type SoraConnection, -} from 'sora-js-sdk' - -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 client = new SoraClient( - SORA_SIGNALING_URL, - SORA_CHANNEL_ID_PREFIX, - SORA_CHANNEL_ID_SUFFIX, - ACCESS_TOKEN, - ) - - document.querySelector('#start')?.addEventListener('click', async () => { - const stream = await navigator.mediaDevices.getUserMedia({ video: false, audio: true }) - - const audioBitRateSelect = document.getElementById('audio-bit-rate') as HTMLSelectElement - const selectedBitRate = audioBitRateSelect.value - ? Number.parseInt(audioBitRateSelect.value) - : undefined - - await client.connect(stream, selectedBitRate) - }) - - document.querySelector('#stop')?.addEventListener('click', async () => { - await client.disconnect() - }) - - document.querySelector('#get-stats')?.addEventListener('click', async () => { - const statsReport = await client.getStats() - const statsDiv = document.querySelector('#stats-report') as HTMLElement - const statsReportJsonDiv = document.querySelector('#stats-report-json') - if (statsDiv && statsReportJsonDiv) { - let statsHtml = '' - const statsReportJson: Record[] = [] - // biome-ignore lint/complexity/noForEach: - statsReport.forEach((report) => { - statsHtml += `

    Type: ${report.type}

    ' - statsReportJson.push(reportJson) - }) - statsDiv.innerHTML = statsHtml - // データ属性としても保存(オプション) - statsDiv.dataset.statsReportJson = JSON.stringify(statsReportJson) - } - }) -}) - -class SoraClient { - private debug = false - private channelId: string - private metadata: { access_token: string } - private options: object = {} - - private sora: SoraConnection - private connection: ConnectionPublisher - - constructor( - signaling_url: string, - channel_id_prefix: string, - channel_id_suffix: string, - access_token: string, - ) { - this.sora = Sora.connection(signaling_url, this.debug) - - // channel_id の生成 - this.channelId = `${channel_id_prefix}sendonly_recvonly${channel_id_suffix}` - // access_token を指定する metadata の生成 - this.metadata = { access_token: access_token } - - this.connection = this.sora.sendonly(this.channelId, this.metadata, this.options) - this.connection.on('notify', this.onnotify.bind(this)) - } - - async connect(stream: MediaStream, audioBitRate?: number): Promise { - if (audioBitRate) { - // 音声ビットレートを上書きする - this.connection.options.audioBitRate = audioBitRate - } - await this.connection.connect(stream) - - const audioElement = document.querySelector('#local-audio') - if (audioElement !== null) { - audioElement.srcObject = stream - } - } - - async disconnect(): Promise { - await this.connection.disconnect() - - const audioElement = document.querySelector('#local-audio') - if (audioElement !== null) { - audioElement.srcObject = null - } - } - - getStats(): Promise { - if (this.connection.pc === null) { - return Promise.reject(new Error('PeerConnection is not ready')) - } - return this.connection.pc.getStats() - } - - private onnotify(event: SignalingNotifyMessage): void { - if ( - event.event_type === 'connection.created' && - this.connection.connectionId === event.connection_id - ) { - const connectionIdElement = document.querySelector('#connection-id') - if (connectionIdElement) { - connectionIdElement.textContent = event.connection_id - } - } - } -} diff --git a/examples/sendonly_audio_codec/index.html b/examples/sendonly_audio_codec/index.html deleted file mode 100644 index 9262f3df..00000000 --- a/examples/sendonly_audio_codec/index.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - Sendonly Audio Codec test - - - -
    -

    Sendonly Audio Codec test

    - - - -
    -
    - - -
    - -
    -
    -
    - - - - \ No newline at end of file diff --git a/examples/sendonly_audio_codec/main.mts b/examples/sendonly_audio_codec/main.mts deleted file mode 100644 index 5bf22ce6..00000000 --- a/examples/sendonly_audio_codec/main.mts +++ /dev/null @@ -1,126 +0,0 @@ -import Sora, { - type SignalingNotifyMessage, - type ConnectionPublisher, - type SoraConnection, -} from 'sora-js-sdk' - -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 client = new SoraClient( - SORA_SIGNALING_URL, - SORA_CHANNEL_ID_PREFIX, - SORA_CHANNEL_ID_SUFFIX, - ACCESS_TOKEN, - ) - - document.querySelector('#start')?.addEventListener('click', async () => { - const stream = await navigator.mediaDevices.getUserMedia({ video: false, audio: true }) - - const audioCodecType = document.getElementById('audio-codec-type') as HTMLSelectElement - const selectedCodecType = audioCodecType.value === 'OPUS' ? audioCodecType.value : undefined - - await client.connect(stream, selectedCodecType) - }) - - document.querySelector('#stop')?.addEventListener('click', async () => { - await client.disconnect() - }) - - document.querySelector('#get-stats')?.addEventListener('click', async () => { - const statsReport = await client.getStats() - const statsDiv = document.querySelector('#stats-report') as HTMLElement - const statsReportJsonDiv = document.querySelector('#stats-report-json') - if (statsDiv && statsReportJsonDiv) { - let statsHtml = '' - const statsReportJson: Record[] = [] - // biome-ignore lint/complexity/noForEach: - statsReport.forEach((report) => { - statsHtml += `

    Type: ${report.type}

      ` - const reportJson: Record = { id: report.id, type: report.type } - for (const [key, value] of Object.entries(report)) { - if (key !== 'type' && key !== 'id') { - statsHtml += `
    • ${key}: ${value}
    • ` - reportJson[key] = value - } - } - statsHtml += '
    ' - statsReportJson.push(reportJson) - }) - statsDiv.innerHTML = statsHtml - // データ属性としても保存(オプション) - statsDiv.dataset.statsReportJson = JSON.stringify(statsReportJson) - } - }) -}) - -class SoraClient { - private debug = false - private channelId: string - private metadata: { access_token: string } - private options: object = {} - - private sora: SoraConnection - private connection: ConnectionPublisher - - constructor( - signaling_url: string, - channel_id_prefix: string, - channel_id_suffix: string, - access_token: string, - ) { - this.sora = Sora.connection(signaling_url, this.debug) - - // channel_id の生成 - this.channelId = `${channel_id_prefix}sendonly_audio_codec${channel_id_suffix}` - // access_token を指定する metadata の生成 - this.metadata = { access_token: access_token } - - this.connection = this.sora.sendonly(this.channelId, this.metadata, this.options) - this.connection.on('notify', this.onnotify.bind(this)) - } - - async connect(stream: MediaStream, audioCodecType?: string): Promise { - if (audioCodecType && audioCodecType === 'OPUS') { - // 音声コーデックを上書きする - this.connection.options.audioCodecType = audioCodecType - } - await this.connection.connect(stream) - - const audioElement = document.querySelector('#local-audio') - if (audioElement !== null) { - audioElement.srcObject = stream - } - } - - async disconnect(): Promise { - await this.connection.disconnect() - - const audioElement = document.querySelector('#local-audio') - if (audioElement !== null) { - audioElement.srcObject = null - } - } - - getStats(): Promise { - if (this.connection.pc === null) { - return Promise.reject(new Error('PeerConnection is not ready')) - } - return this.connection.pc.getStats() - } - - private onnotify(event: SignalingNotifyMessage): void { - if ( - event.event_type === 'connection.created' && - this.connection.connectionId === event.connection_id - ) { - const connectionIdElement = document.querySelector('#connection-id') - if (connectionIdElement) { - connectionIdElement.textContent = event.connection_id - } - } - } -} diff --git a/tests/sendonly_audio_bit_rate.spec.ts b/tests/sendonly_audio_bit_rate.spec.ts deleted file mode 100644 index a3bae430..00000000 --- a/tests/sendonly_audio_bit_rate.spec.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { expect, test } from '@playwright/test' - -test('sendonly bit rate pages', async ({ browser }) => { - // 新しいページを作成 - const sendonly = await browser.newPage() - // ページに対して操作を行う - await sendonly.goto('http://localhost:9000/sendonly_audio_bit_rate/') - - // select 要素から直接オプションを取得してランダムに選択 - const randomBitrate = await sendonly.evaluate(() => { - const select = document.querySelector('#audio-bit-rate') as HTMLSelectElement - const options = Array.from(select.options).filter((option) => option.value !== '') // 未指定を除外 - const randomOption = options[Math.floor(Math.random() * options.length)] - select.value = randomOption.value - return randomOption.value - }) - - // ログで選択されたビットレートを表示 - console.log(`Selected bitrate: ${randomBitrate} kbps`) - - await sendonly.click('#start') - // #connection-id 要素が存在し、その内容が空でないことを確認するまで待つ - await sendonly.waitForSelector('#connection-id:not(:empty)') - // #connection-id 要素の内容を取得 - const sendonlyConnectionId = await sendonly.$eval('#connection-id', (el) => el.textContent) - console.log(`sendonly connectionId=${sendonlyConnectionId}`) - - // レース対策 - await sendonly.waitForTimeout(3000) - - // 'Get Stats' ボタンをクリックして統計情報を取得 - await sendonly.click('#get-stats') - // 統計情報が表示されるまで待機 - await sendonly.waitForSelector('#stats-report') - - // データセットから統計情報を取得 - const sendonlyStatsReportJson: Record[] = await sendonly.evaluate(() => { - const statsReportDiv = document.querySelector('#stats-report') as HTMLDivElement - return statsReportDiv ? JSON.parse(statsReportDiv.dataset.statsReportJson || '[]') : [] - }) - - const sendonlyAudioCodecStats = sendonlyStatsReportJson.find( - (report) => report.type === 'codec' && report.mimeType === 'audio/opus', - ) - expect(sendonlyAudioCodecStats).toBeDefined() - const sendonlyAudioOutboundRtp = sendonlyStatsReportJson.find( - (report) => report.type === 'outbound-rtp' && report.kind === 'audio', - ) - expect(sendonlyAudioOutboundRtp).toBeDefined() - expect(sendonlyAudioOutboundRtp?.bytesSent).toBeGreaterThan(0) - expect(sendonlyAudioOutboundRtp?.packetsSent).toBeGreaterThan(0) - - // 選択されたビットレートに基づいて期待値を設定 - const expectedBitrate = Number.parseInt(randomBitrate) * 1000 - expect(sendonlyAudioOutboundRtp?.targetBitrate).toEqual(expectedBitrate) - - await sendonly.click('#stop') - await sendonly.close() -}) diff --git a/tests/sendonly_audio_codec.spec.ts b/tests/sendonly_audio_codec.spec.ts deleted file mode 100644 index b41ff186..00000000 --- a/tests/sendonly_audio_codec.spec.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { expect, test } from '@playwright/test' - -test('sendonly audio codec type pages', async ({ browser }) => { - const sendonly = await browser.newPage() - await sendonly.goto('http://localhost:9000/sendonly_audio_codec/') - - // select 要素から直接オプションを取得してランダムに選択 - const randomAudioCodec = await sendonly.evaluate(() => { - const select = document.querySelector('#audio-codec-type') as HTMLSelectElement - const options = Array.from(select.options) - const randomOption = options[Math.floor(Math.random() * options.length)] - select.value = randomOption.value - return randomOption.value - }) - - // 選択したコーデックタイプをログに出力 - console.log('Selected codec:', randomAudioCodec) - - // Start ボタンクリック - await sendonly.click('#start') - await sendonly.waitForSelector('#connection-id:not(:empty)') - - // #connection-id 要素の内容を取得 - const sendonlyConnectionId = await sendonly.$eval('#connection-id', (el) => el.textContent) - console.log(`Selected codec: connectionId=${sendonlyConnectionId}`) - - // レース対策 - await sendonly.waitForTimeout(3000) - - // 'Get Stats' ボタンをクリックして統計情報を取得 - await sendonly.click('#get-stats') - // 統計情報が表示されるまで待機 - await sendonly.waitForSelector('#stats-report') - - // データセットから統計情報を取得 - const sendonlyStatsReportJson: Record[] = await sendonly.evaluate(() => { - const statsReportDiv = document.querySelector('#stats-report') as HTMLDivElement - return statsReportDiv ? JSON.parse(statsReportDiv.dataset.statsReportJson || '[]') : [] - }) - - const sendonlyAudioCodecStats = sendonlyStatsReportJson.find( - (report) => report.type === 'codec' && report.mimeType === 'audio/opus', - ) - - // 今は指定してもしなくても OPUS のみ - expect(sendonlyAudioCodecStats).toBeDefined() - const sendonlyAudioOutboundRtp = sendonlyStatsReportJson.find( - (report) => report.type === 'outbound-rtp' && report.kind === 'audio', - ) - // 音声が正常に送れているかの確認 - expect(sendonlyAudioOutboundRtp).toBeDefined() - expect(sendonlyAudioOutboundRtp?.bytesSent).toBeGreaterThan(0) - expect(sendonlyAudioOutboundRtp?.packetsSent).toBeGreaterThan(0) - - await sendonly.click('#stop') - await sendonly.close() -})