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}
`
- 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_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()
-})