diff --git a/.github/workflows/wpt-smoke.yml b/.github/workflows/wpt-smoke.yml new file mode 100644 index 000000000..d6bd0cd87 --- /dev/null +++ b/.github/workflows/wpt-smoke.yml @@ -0,0 +1,19 @@ +name: WPT Smoke + +on: + pull_request: + workflow_dispatch: + +jobs: + wpt-smoke: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup + uses: ./.github/actions/setup + + - name: Build and run WPT smoke + working-directory: packages/react-native-audio-api + run: yarn wpt diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/utils/NodeOptionsParser.h b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/utils/NodeOptionsParser.h index 6a7744437..002f024e5 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/utils/NodeOptionsParser.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/utils/NodeOptionsParser.h @@ -116,10 +116,12 @@ inline ConvolverOptions parseConvolverOptions( } if (optionsObject.hasProperty(runtime, "buffer")) { - auto bufferHostObject = optionsObject.getProperty(runtime, "buffer") - .getObject(runtime) - .asHostObject(runtime); - options.buffer = bufferHostObject->audioBuffer_; + auto bufferValue = optionsObject.getProperty(runtime, "buffer"); + if (bufferValue.isObject() && + bufferValue.getObject(runtime).isHostObject(runtime)) { + options.buffer = + bufferValue.getObject(runtime).asHostObject(runtime)->audioBuffer_; + } } return options; } @@ -285,10 +287,12 @@ inline AudioBufferSourceOptions parseAudioBufferSourceOptions( AudioBufferSourceOptions options(parseBaseAudioBufferSourceOptions(runtime, optionsObject)); if (optionsObject.hasProperty(runtime, "buffer")) { - auto bufferHostObject = optionsObject.getProperty(runtime, "buffer") - .getObject(runtime) - .asHostObject(runtime); - options.buffer = bufferHostObject->audioBuffer_; + auto bufferValue = optionsObject.getProperty(runtime, "buffer"); + if (bufferValue.isObject() && + bufferValue.getObject(runtime).isHostObject(runtime)) { + options.buffer = + bufferValue.getObject(runtime).asHostObject(runtime)->audioBuffer_; + } } auto loopValue = optionsObject.getProperty(runtime, "loop"); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/AudioContext.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/AudioContext.cpp index 77dc9d351..b6f726a4c 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/AudioContext.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/AudioContext.cpp @@ -1,4 +1,6 @@ -#ifdef ANDROID +#ifdef RN_AUDIO_API_NODE +#include "NodeAudioPlayer.h" +#elif defined(ANDROID) #include #else #include @@ -25,7 +27,12 @@ AudioContext::~AudioContext() { void AudioContext::initialize(const AudioDestinationNode *destination) { BaseAudioContext::initialize(destination); -#ifdef ANDROID +#ifdef RN_AUDIO_API_NODE + audioPlayer_ = std::make_shared( + [this](DSPAudioBuffer *buf, int n) { processGraph(buf, n); }, + getSampleRate(), + destination_->getChannelCount()); +#elif defined(ANDROID) audioPlayer_ = std::make_shared( [this](DSPAudioBuffer *buf, int n) { processGraph(buf, n); }, getSampleRate(), diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/AudioContext.h b/packages/react-native-audio-api/common/cpp/audioapi/core/AudioContext.h index 88ec77584..27ddecfea 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/AudioContext.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/AudioContext.h @@ -10,7 +10,9 @@ #include namespace audioapi { -#ifdef ANDROID +#ifdef RN_AUDIO_API_NODE +class NodeAudioPlayer; +#elif defined(ANDROID) class AudioPlayer; #else class IOSAudioPlayer; @@ -36,7 +38,9 @@ class AudioContext : public BaseAudioContext { void initialize(const AudioDestinationNode *destination) final; private: -#ifdef ANDROID +#ifdef RN_AUDIO_API_NODE + std::shared_ptr audioPlayer_; +#elif defined(ANDROID) std::shared_ptr audioPlayer_; #else std::shared_ptr audioPlayer_; diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp index 73b5a4416..ad1f50159 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp @@ -65,19 +65,27 @@ void AudioBufferSourceNode::setBuffer( context->getDisposer()->dispose(std::move(buffer_)); } - if (audioBuffer_ != nullptr) { - context->getDisposer()->dispose(std::move(audioBuffer_)); - } - if (buffer == nullptr) { loopEnd_ = 0; channelCount_ = 1; buffer_ = nullptr; processor_->setBuffer(nullptr); + if (audioBuffer_ != nullptr) { + context->getDisposer()->dispose(std::move(audioBuffer_)); + } + // Replace the (possibly shared with the previous AudioBuffer) output + // buffer with a fresh one so processNode() can output silence without + // touching the old buffer's data. + audioBuffer_ = std::make_shared( + RENDER_QUANTUM_SIZE, channelCount_, context->getSampleRate()); return; } + if (audioBuffer_ != nullptr) { + context->getDisposer()->dispose(std::move(audioBuffer_)); + } + buffer_ = buffer; audioBuffer_ = audioBuffer; channelCount_ = static_cast(buffer_->getNumberOfChannels()); diff --git a/packages/react-native-audio-api/package.json b/packages/react-native-audio-api/package.json index e55341b84..c25130950 100644 --- a/packages/react-native-audio-api/package.json +++ b/packages/react-native-audio-api/package.json @@ -10,8 +10,17 @@ "module": "lib/module/index", "react-native": "src/index", "types": "lib/typescript/index.d.ts", + "exports": { + ".": { + "types": "./lib/typescript/index.d.ts", + "react-native": "./src/index", + "node": "./wpt_tests/index.js", + "default": "./lib/module/index" + } + }, "files": [ "src/", + "wpt_tests/", "development/react/", "mock/", "lib/", @@ -70,6 +79,12 @@ "format:ios": "find ios/audioapi/ios -type f \\( -iname \"*.h\" -o -iname \"*.m\" -o -iname \"*.mm\" \\) | xargs clang-format -i", "format:common": "find common/cpp/ \\( -path 'common/cpp/audioapi/libs' -prune -o -path 'common/cpp/audioapi/external' -prune -o -type f \\( -iname \"*.h\" -o -iname \"*.cpp\" -o -iname \"*.hpp\" \\) -print \\) | xargs clang-format -i", "build": "bob build", + "node:build": "cmake-js compile -d wpt_tests", + "wpt:build": "yarn build && yarn node:build", + "wpt:only": "node ./wpt_tests/wpt/wpt-harness.mjs", + "wpt": "yarn wpt:build && yarn wpt:only", + "wpt:list": "node ./wpt_tests/wpt/wpt-harness.mjs --list", + "wpt:filter": "node ./wpt_tests/wpt/wpt-harness.mjs --filter", "create:package": "./scripts/create-package.sh", "prepack": "cp ../../README.md ./README.md", "postpack": "rm ./README.md" @@ -129,6 +144,9 @@ "@types/react-test-renderer": "^19.1.0", "@types/semver": "7.7.1", "babel-plugin-module-resolver": "^4.1.0", + "chalk": "^5.3.0", + "cmake-js": "^7.3.1", + "commander": "^14.0.0", "commitlint": "17.0.2", "del-cli": "^5.1.0", "eslint": "^8.57.0", @@ -145,13 +163,15 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-standard": "^5.0.0", "eslint-plugin-tsdoc": "^0.2.17", + "hermes-engine": "^0.11.0", "jest": "^29.7.0", "prettier": "^3.3.3", "react": "19.2.3", "react-native": "0.85.0", "react-native-builder-bob": "0.33.1", "turbo": "^1.10.7", - "typescript": "~6.0.3" + "typescript": "~6.0.3", + "wpt-runner": "^7.0.0" }, "react-native-builder-bob": { "source": "src", diff --git a/packages/react-native-audio-api/src/core/AudioBuffer.ts b/packages/react-native-audio-api/src/core/AudioBuffer.ts index ebff66d0a..7124c819f 100644 --- a/packages/react-native-audio-api/src/core/AudioBuffer.ts +++ b/packages/react-native-audio-api/src/core/AudioBuffer.ts @@ -1,6 +1,10 @@ import { AudioBufferLike, AudioBufferOptions } from '../types'; import { IAudioBuffer } from '../jsi-interfaces'; -import { IndexSizeError, NotSupportedError } from '../errors'; +import { + IndexSizeError, + NotSupportedError, + wrapFloat32ArrayView, +} from '../errors'; export default class AudioBuffer implements AudioBufferLike { readonly length: number; @@ -32,7 +36,9 @@ export default class AudioBuffer implements AudioBufferLike { `The channel number provided (${channel}) is outside the range [0, ${this.numberOfChannels - 1}]` ); } - return this.buffer.getChannelData(channel); + return wrapFloat32ArrayView( + this.buffer.getChannelData(channel) + ) as Float32Array; } public copyFromChannel( @@ -40,6 +46,7 @@ export default class AudioBuffer implements AudioBufferLike { channelNumber: number, startInChannel: number = 0 ): void { + AudioBuffer.assertFloat32Array(destination, 'destination'); if (channelNumber < 0 || channelNumber >= this.numberOfChannels) { throw new IndexSizeError( `The channel number provided (${channelNumber}) is outside the range [0, ${this.numberOfChannels - 1}]` @@ -60,6 +67,7 @@ export default class AudioBuffer implements AudioBufferLike { channelNumber: number, startInChannel: number = 0 ): void { + AudioBuffer.assertFloat32Array(source, 'source'); if (channelNumber < 0 || channelNumber >= this.numberOfChannels) { throw new IndexSizeError( `The channel number provided (${channelNumber}) is outside the range [0, ${this.numberOfChannels - 1}]` @@ -75,6 +83,31 @@ export default class AudioBuffer implements AudioBufferLike { this.buffer.copyToChannel(source, channelNumber, startInChannel); } + private static assertFloat32Array(value: unknown, name: string): void { + // Cross-realm Float32Arrays (e.g. from a jsdom window) fail instanceof, + // so also accept any object that looks like a Float32Array view. + const isFloat32View = + value instanceof Float32Array || + (typeof value === 'object' && + value !== null && + ArrayBuffer.isView(value as ArrayBufferView) && + (value as Float32Array).BYTES_PER_ELEMENT === 4 && + (value.constructor as { name?: string })?.name === 'Float32Array'); + + if (!isFloat32View) { + throw new TypeError(`The provided ${name} is not a Float32Array`); + } + + const backingBuffer = (value as Float32Array).buffer as { + constructor?: { name?: string }; + }; + if (backingBuffer?.constructor?.name === 'SharedArrayBuffer') { + throw new TypeError( + `The provided ${name} is backed by a SharedArrayBuffer, which is not allowed` + ); + } + } + private static createBufferFromOptions( options: AudioBufferOptions ): IAudioBuffer { diff --git a/packages/react-native-audio-api/src/core/AudioBufferSourceNode.ts b/packages/react-native-audio-api/src/core/AudioBufferSourceNode.ts index 9572a1ab5..7dd481171 100644 --- a/packages/react-native-audio-api/src/core/AudioBufferSourceNode.ts +++ b/packages/react-native-audio-api/src/core/AudioBufferSourceNode.ts @@ -13,12 +13,14 @@ export default class AudioBufferSourceNode extends AudioBufferBaseSourceNode { private bufferHasBeenSet: boolean = false; constructor(context: BaseAudioContext, options?: AudioBufferSourceOptions) { - const node = context.context.createBufferSource(options || {}); + // The native layer expects the AudioBuffer HostObject, not the TS wrapper, + // so pass the buffer through the setter below instead of the options. + const { buffer, ...nativeOptions } = options ?? {}; + const node = context.context.createBufferSource(nativeOptions); super(context, node); - if (options?.buffer) { - this._buffer = options.buffer as AudioBuffer; - this.bufferHasBeenSet = true; + if (buffer != null) { + this.buffer = buffer as AudioBuffer; } } @@ -36,6 +38,12 @@ export default class AudioBufferSourceNode extends AudioBufferBaseSourceNode { return; } + if (!(buffer instanceof AudioBuffer)) { + throw new TypeError( + 'Failed to set buffer: the provided value is not of type AudioBuffer.' + ); + } + if (this.bufferHasBeenSet) { throw new InvalidStateError( 'The buffer can only be set once and cannot be changed afterwards.' diff --git a/packages/react-native-audio-api/src/errors/createFloat32ArrayView.ts b/packages/react-native-audio-api/src/errors/createFloat32ArrayView.ts new file mode 100644 index 000000000..a182a3a6a --- /dev/null +++ b/packages/react-native-audio-api/src/errors/createFloat32ArrayView.ts @@ -0,0 +1,21 @@ +type Float32ArrayViewFactory = ( + buffer: ArrayBufferLike, + byteOffset: number, + length: number +) => Float32Array; + +let float32ArrayViewFactory: Float32ArrayViewFactory | undefined; + +export function setFloat32ArrayViewFactory( + factory: Float32ArrayViewFactory +): void { + float32ArrayViewFactory = factory; +} + +export function wrapFloat32ArrayView(view: Float32Array): Float32Array { + if (float32ArrayViewFactory == null) { + return view; + } + + return float32ArrayViewFactory(view.buffer, view.byteOffset, view.length); +} diff --git a/packages/react-native-audio-api/src/errors/index.ts b/packages/react-native-audio-api/src/errors/index.ts index 30efd3d5b..184406c16 100644 --- a/packages/react-native-audio-api/src/errors/index.ts +++ b/packages/react-native-audio-api/src/errors/index.ts @@ -1,3 +1,7 @@ +export { + setFloat32ArrayViewFactory, + wrapFloat32ArrayView, +} from './createFloat32ArrayView'; export { default as IndexSizeError } from './IndexSizeError'; export { default as InvalidAccessError } from './InvalidAccessError'; export { default as InvalidStateError } from './InvalidStateError'; diff --git a/packages/react-native-audio-api/wpt_tests/.clangd b/packages/react-native-audio-api/wpt_tests/.clangd new file mode 100644 index 000000000..ec0b89036 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/.clangd @@ -0,0 +1,2 @@ +CompileFlags: + CompilationDatabase: build diff --git a/packages/react-native-audio-api/wpt_tests/CMakeLists.txt b/packages/react-native-audio-api/wpt_tests/CMakeLists.txt new file mode 100644 index 000000000..f49d8de5d --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/CMakeLists.txt @@ -0,0 +1,118 @@ +cmake_minimum_required(VERSION 3.14) +project(rnaudioapi_node_bindings) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +set(PACKAGE_ROOT ${CMAKE_SOURCE_DIR}/..) +set(ROOT ${PACKAGE_ROOT}/../..) +set(REACT_NATIVE_DIR "${ROOT}/node_modules/react-native") +set(JSI_DIR "${REACT_NATIVE_DIR}/ReactCommon/jsi") +set(JSI_IMPL_DIR "${JSI_DIR}/jsi") +set(FFMPEG_INCLUDE_DIR "${PACKAGE_ROOT}/common/cpp/audioapi/external/include_ffmpeg") +include(FetchContent) + +FetchContent_Declare( + node_api_jsi + GIT_REPOSITORY https://github.com/microsoft/node-api-jsi.git + GIT_TAG main + GIT_SHALLOW TRUE +) +FetchContent_GetProperties(node_api_jsi) +if(NOT node_api_jsi_POPULATED) + FetchContent_Populate(node_api_jsi) +endif() + +set(NODE_API_JSI_RUNTIME_SRC "${node_api_jsi_SOURCE_DIR}/src/NodeApiJsiRuntime.cpp") +set(NODE_API_JSI_RUNTIME_PATCHED_DIR "${CMAKE_BINARY_DIR}/generated/node_api_jsi") +set(NODE_API_JSI_RUNTIME_PATCHED_SRC "${NODE_API_JSI_RUNTIME_PATCHED_DIR}/NodeApiJsiRuntime.cpp") +file(MAKE_DIRECTORY "${NODE_API_JSI_RUNTIME_PATCHED_DIR}") +file(READ "${NODE_API_JSI_RUNTIME_SRC}" NODE_API_JSI_RUNTIME_CONTENT) +set(NODE_API_JSI_SET_TRAP_ORIGINAL +" runInMethodContext( + \"HostObject::set\", [&hostObject, &propertyId, &value, this]() { + hostObject->set(*this, propertyId, value); + }); + return getUndefined();") +set(NODE_API_JSI_SET_TRAP_PATCHED +" runInMethodContext( + \"HostObject::set\", [&hostObject, &propertyId, &value, this]() { + hostObject->set(*this, propertyId, value); + }); + return getBoolean(true);") +string(REPLACE + "${NODE_API_JSI_SET_TRAP_ORIGINAL}" + "${NODE_API_JSI_SET_TRAP_PATCHED}" + NODE_API_JSI_RUNTIME_CONTENT + "${NODE_API_JSI_RUNTIME_CONTENT}") +file(WRITE "${NODE_API_JSI_RUNTIME_PATCHED_SRC}" "${NODE_API_JSI_RUNTIME_CONTENT}") + +file(GLOB_RECURSE RNAUDIOAPI_COMMON_SOURCES + CONFIGURE_DEPENDS + "${PACKAGE_ROOT}/common/cpp/audioapi/*.cpp" +) + +list(FILTER RNAUDIOAPI_COMMON_SOURCES EXCLUDE REGEX ".*/android/.*\\.cpp$") +list(FILTER RNAUDIOAPI_COMMON_SOURCES EXCLUDE REGEX ".*/ios/.*\\.cpp$") +list(FILTER RNAUDIOAPI_COMMON_SOURCES EXCLUDE REGEX ".*/ios/.*\\.mm$") +list(FILTER RNAUDIOAPI_COMMON_SOURCES EXCLUDE REGEX ".*/HostObjects/inputs/AudioRecorderHostObject\\.cpp$") + +list(APPEND RNAUDIOAPI_COMMON_SOURCES + "${CMAKE_SOURCE_DIR}/src/addon_init.cpp" + "${CMAKE_SOURCE_DIR}/src/NodeJSRuntimeApi.cpp" + "${CMAKE_SOURCE_DIR}/src/jsi_install.cpp" + "${CMAKE_SOURCE_DIR}/src/SyncCallInvoker.cpp" + "${CMAKE_SOURCE_DIR}/src/NodeAudioPlayer.cpp" + "${NODE_API_JSI_RUNTIME_PATCHED_SRC}" + "${node_api_jsi_SOURCE_DIR}/src/ApiLoaders/NodeApi.cpp" + "${node_api_jsi_SOURCE_DIR}/src/ApiLoaders/JSRuntimeApi.cpp" + "${JSI_IMPL_DIR}/jsi.cpp" + "${JSI_IMPL_DIR}/jsilib-posix.cpp" +) + +file(GLOB_RECURSE RNAUDIOAPI_LIB_SOURCES + CONFIGURE_DEPENDS + "${PACKAGE_ROOT}/common/cpp/audioapi/libs/*.c" +) + +add_library(${PROJECT_NAME} SHARED + ${RNAUDIOAPI_COMMON_SOURCES} + ${RNAUDIOAPI_LIB_SOURCES} +) + +set_target_properties(${PROJECT_NAME} + PROPERTIES + PREFIX "" + SUFFIX ".node" +) + +target_compile_definitions(${PROJECT_NAME} PRIVATE + JSI_VERSION=21 + RN_AUDIO_API_NODE=1 + RN_AUDIO_API_ENABLE_WORKLETS=0 + RN_AUDIO_API_FFMPEG_DISABLED=1 + RN_AUDIO_API_STATIC_EXTERNAL_LIBS_DISABLED=1 + MA_NO_LIBOPUS=1 + MA_NO_LIBVORBIS=1 +) + +target_include_directories(${PROJECT_NAME} PRIVATE + ${PACKAGE_ROOT}/common/cpp + ${FFMPEG_INCLUDE_DIR} + "${FFMPEG_INCLUDE_DIR}/libavcodec" + "${FFMPEG_INCLUDE_DIR}/libavformat" + "${FFMPEG_INCLUDE_DIR}/libavutil" + "${FFMPEG_INCLUDE_DIR}/libswresample" + "${node_api_jsi_SOURCE_DIR}/src" + "${node_api_jsi_SOURCE_DIR}/node-api" + ${CMAKE_SOURCE_DIR}/src + ${JSI_DIR} + "${REACT_NATIVE_DIR}/ReactCommon" + "${REACT_NATIVE_DIR}/ReactCommon/callinvoker" + ${CMAKE_JS_INC} +) + +target_link_libraries(${PROJECT_NAME} + ${CMAKE_JS_LIB} +) diff --git a/packages/react-native-audio-api/wpt_tests/README.md b/packages/react-native-audio-api/wpt_tests/README.md new file mode 100644 index 000000000..5ffe53947 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/README.md @@ -0,0 +1,49 @@ +# Node Bindings (JSI-only) + +This directory contains the Node.js bootstrap for running Web Audio WPT against +`react-native-audio-api`. + +## What this provides + +- Native Node addon (`wpt_tests/src`) using JSI HostObjects via `node-api-jsi`. +- JSI-backed runtime installation (`jsi_install.cpp`). +- Smoke WPT harness (`wpt_tests/wpt/wpt-harness.mjs`) with allowlist + skip policy. +- Vendored Web Audio API tests under `wpt_tests/webaudio/` (~3 MB, full `webaudio` subtree). + +## Prerequisites + +- Node.js 22+ +- CMake 3.14+ +- Monorepo dependencies installed (`yarn install` at repo root) + +## Local workflow + +From `packages/react-native-audio-api`: + +1. Build JS + native addon: + - `yarn wpt:build` +2. List selected smoke tests: + - `yarn wpt:list` +3. Run smoke WPT: + - `yarn wpt` +4. Run filtered subset: + - `node ./wpt_tests/wpt/wpt-harness.mjs --filter gain` +5. Run in parallel (one worker process per test class, up to N concurrent): + - `node ./wpt_tests/wpt/wpt-harness.mjs --jobs 4` + - `node ./wpt_tests/wpt/wpt-harness.mjs --jobs auto --filter the-gainnode-interface` + +## Troubleshooting + +- **Native addon fails to load** + - Rebuild with `yarn node:build`. +- **Device-related instability in CI** + - Node test backend is sink-less; keep tests within the smoke profile. +- **Runner appears hung** + - Kill stale processes: `pkill -f wpt-harness.mjs` + - Some tests are excluded in `wpt/skip-list.json` (crashtests, AudioWorklet, known engine hangs). +- **Subset runs** + - `yarn wpt --filter gain` or `node ./wpt_tests/wpt/wpt-harness.mjs --filter the-analysernode-interface` + +## Scope + +The Node harness exports only spec Web Audio API classes via `wpt-api.js` (no recorder, decoder, streamer, or worklet nodes). Failures for unimplemented spec APIs (e.g. `PannerNode`, `ChannelMergerNode`) are expected until those nodes land. diff --git a/packages/react-native-audio-api/wpt_tests/index.js b/packages/react-native-audio-api/wpt_tests/index.js new file mode 100644 index 000000000..71c0ecb4f --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/index.js @@ -0,0 +1,83 @@ +'use strict'; + +const Module = require('node:module'); +const path = require('node:path'); + +require('./native-module'); + +const mediaDevices = { + async getUserMedia() { + throw new Error('mediaDevices.getUserMedia is not supported in Node phase-1 bindings.'); + }, +}; + +function loadTypeScriptApi() { + // eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-dynamic-require, global-require + return require(path.join(__dirname, 'wpt-api.js')); +} + +function installReactNativeNodeShim() { + const globalAny = global; + if (globalAny.__RNAudioApiReactNativeShimInstalled === true) { + return; + } + + const nativeModuleStub = { + install() { + return true; + }, + getDevicePreferredSampleRate() { + return 44100; + }, + isFfmpegEnabled() { + return false; + }, + }; + + const reactNativeShim = { + TurboModuleRegistry: { + get() { + return nativeModuleStub; + }, + getEnforcing() { + return nativeModuleStub; + }, + }, + Platform: { OS: 'ios' }, + Image: { + resolveAssetSource(assetId) { + return { uri: String(assetId) }; + }, + }, + }; + + const originalLoad = Module._load; + Module._load = function patchedLoad(request, parent, isMain) { + if (request === 'react-native') { + return reactNativeShim; + } + return originalLoad.call(this, request, parent, isMain); + }; + + if (globalAny.__DEV__ == null) { + globalAny.__DEV__ = false; + } + + if (globalAny.__RNAudioAPINativeModule == null) { + globalAny.__RNAudioAPINativeModule = { + getDevicePreferredSampleRate() { + return 44100; + }, + }; + } + + globalAny.__RNAudioApiReactNativeShimInstalled = true; +} + +installReactNativeNodeShim(); + +const typeScriptApi = loadTypeScriptApi(); +module.exports = { + ...typeScriptApi, + mediaDevices, +}; diff --git a/packages/react-native-audio-api/wpt_tests/load-native.js b/packages/react-native-audio-api/wpt_tests/load-native.js new file mode 100644 index 000000000..39043b99f --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/load-native.js @@ -0,0 +1,32 @@ +'use strict'; + +const fs = require('node:fs'); +const path = require('node:path'); + +function getCandidates() { + const packageRoot = path.resolve(__dirname, '..'); + const bindingsName = 'rnaudioapi_node_bindings.node'; + + return [ + // Current layout after node -> wpt_tests rename. + path.join(__dirname, 'build', 'Release', bindingsName), + path.join(__dirname, 'build', 'Debug', bindingsName), + // Backward compatibility with older package layouts. + path.join(packageRoot, 'node', 'build', 'Release', bindingsName), + path.join(packageRoot, 'node', 'build', 'Debug', bindingsName), + path.join(packageRoot, 'build', 'Release', bindingsName), + path.join(packageRoot, 'build', 'Debug', bindingsName), + ]; +} + +function loadNative() { + for (const filePath of getCandidates()) { + if (fs.existsSync(filePath)) { + // eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-dynamic-require, global-require + return require(filePath); + } + } + return null; +} + +module.exports = loadNative; diff --git a/packages/react-native-audio-api/wpt_tests/native-module.js b/packages/react-native-audio-api/wpt_tests/native-module.js new file mode 100644 index 000000000..817ab8735 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/native-module.js @@ -0,0 +1,20 @@ +'use strict'; + +const loadNative = require('./load-native'); + +const nativeBinding = loadNative(); +if (nativeBinding == null || nativeBinding.nativeModule == null) { + throw new Error('Failed to load Node native bindings for react-native-audio-api.'); +} + +const install = nativeBinding.nativeModule.install; +if (typeof install !== 'function') { + throw new Error('Node native bindings are missing install() entrypoint.'); +} + +const installed = Boolean(install()); +if (!installed) { + throw new Error('Node native bindings install() returned false.'); +} + +module.exports = { installed }; diff --git a/packages/react-native-audio-api/wpt_tests/src/NodeAudioPlayer.cpp b/packages/react-native-audio-api/wpt_tests/src/NodeAudioPlayer.cpp new file mode 100644 index 000000000..07462d00b --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/src/NodeAudioPlayer.cpp @@ -0,0 +1,100 @@ +#include "NodeAudioPlayer.h" + +#include + +#include +#include + +namespace audioapi { + +NodeAudioPlayer::NodeAudioPlayer( + const std::function &renderAudio, + float sampleRate, + int channelCount) + : renderAudio_(renderAudio), + buffer_(std::make_shared(RENDER_QUANTUM_SIZE, channelCount, sampleRate)), + sampleRate_(sampleRate), + channelCount_(channelCount) {} + +NodeAudioPlayer::~NodeAudioPlayer() { + stop(); +} + +bool NodeAudioPlayer::start() { + if (isInitialized_.load(std::memory_order_acquire)) { + return false; + } + + shouldStop_.store(false, std::memory_order_release); + isPaused_.store(false, std::memory_order_release); + isRunning_.store(true, std::memory_order_release); + isInitialized_.store(true, std::memory_order_release); + + worker_ = std::thread(&NodeAudioPlayer::run, this); + return true; +} + +void NodeAudioPlayer::stop() { + if (!isInitialized_.load(std::memory_order_acquire)) { + return; + } + + shouldStop_.store(true, std::memory_order_release); + isPaused_.store(true, std::memory_order_release); + isRunning_.store(false, std::memory_order_release); + + if (worker_.joinable()) { + worker_.join(); + } +} + +bool NodeAudioPlayer::resume() { + if (!isInitialized_.load(std::memory_order_acquire)) { + return false; + } + + if (isRunning_.load(std::memory_order_acquire)) { + return true; + } + + isPaused_.store(false, std::memory_order_release); + isRunning_.store(true, std::memory_order_release); + return true; +} + +void NodeAudioPlayer::suspend() { + if (!isInitialized_.load(std::memory_order_acquire)) { + return; + } + + isPaused_.store(true, std::memory_order_release); + isRunning_.store(false, std::memory_order_release); +} + +void NodeAudioPlayer::cleanup() { + stop(); + isInitialized_.store(false, std::memory_order_release); +} + +bool NodeAudioPlayer::isRunning() const { + return isRunning_.load(std::memory_order_acquire); +} + +void NodeAudioPlayer::run() { + const auto sampleRate = std::max(sampleRate_, 1.0f); + const auto quantumDuration = std::chrono::microseconds(static_cast( + (static_cast(RENDER_QUANTUM_SIZE) * 1'000'000.0) / sampleRate)); + + while (!shouldStop_.load(std::memory_order_acquire)) { + if (isPaused_.load(std::memory_order_acquire)) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + continue; + } + + buffer_->zero(); + renderAudio_(buffer_.get(), RENDER_QUANTUM_SIZE); + std::this_thread::sleep_for(quantumDuration); + } +} + +} // namespace audioapi diff --git a/packages/react-native-audio-api/wpt_tests/src/NodeAudioPlayer.h b/packages/react-native-audio-api/wpt_tests/src/NodeAudioPlayer.h new file mode 100644 index 000000000..fa4910fc4 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/src/NodeAudioPlayer.h @@ -0,0 +1,42 @@ +#pragma once + +#include + +#include +#include +#include +#include + +namespace audioapi { + +class NodeAudioPlayer final { + public: + NodeAudioPlayer( + const std::function &renderAudio, + float sampleRate, + int channelCount); + ~NodeAudioPlayer(); + + bool start(); + void stop(); + bool resume(); + void suspend(); + void cleanup(); + + [[nodiscard]] bool isRunning() const; + + private: + void run(); + + std::function renderAudio_; + std::shared_ptr buffer_; + float sampleRate_; + int channelCount_; + std::atomic isInitialized_{false}; + std::atomic isRunning_{false}; + std::atomic isPaused_{true}; + std::atomic shouldStop_{false}; + std::thread worker_; +}; + +} // namespace audioapi diff --git a/packages/react-native-audio-api/wpt_tests/src/NodeJSRuntimeApi.cpp b/packages/react-native-audio-api/wpt_tests/src/NodeJSRuntimeApi.cpp new file mode 100644 index 000000000..a883b2182 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/src/NodeJSRuntimeApi.cpp @@ -0,0 +1,29 @@ +#include "NodeJSRuntimeApi.h" + +#include + +namespace rnaudioapi::node { + +namespace { +using Microsoft::NodeApiJsi::FuncPtr; +} // namespace + +NodeJSRuntimeApi::NodeJSRuntimeApi() : api_(&resolver_) {} + +Microsoft::NodeApiJsi::JSRuntimeApi *NodeJSRuntimeApi::api() { + return &api_; +} + +FuncPtr NodeJSRuntimeApi::ProcessSymbolResolver::getFuncPtr(const char *funcName) { +#define NODE_API_FUNC(func) \ + if (std::strcmp(funcName, #func) == 0) { \ + return reinterpret_cast(&func); \ + } +#include + + // Returning nullptr for jsr_* is intentional: JSRuntimeApi uses + // built-in defaults for missing JSR symbols. + return nullptr; +} + +} // namespace rnaudioapi::node diff --git a/packages/react-native-audio-api/wpt_tests/src/NodeJSRuntimeApi.h b/packages/react-native-audio-api/wpt_tests/src/NodeJSRuntimeApi.h new file mode 100644 index 000000000..682a8474e --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/src/NodeJSRuntimeApi.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +namespace rnaudioapi::node { + +class NodeJSRuntimeApi final { + public: + NodeJSRuntimeApi(); + + Microsoft::NodeApiJsi::JSRuntimeApi *api(); + + private: + class ProcessSymbolResolver final : public Microsoft::NodeApiJsi::IFuncResolver { + public: + Microsoft::NodeApiJsi::FuncPtr getFuncPtr(const char *funcName) override; + }; + + ProcessSymbolResolver resolver_; + Microsoft::NodeApiJsi::JSRuntimeApi api_; +}; + +} // namespace rnaudioapi::node diff --git a/packages/react-native-audio-api/wpt_tests/src/SyncCallInvoker.cpp b/packages/react-native-audio-api/wpt_tests/src/SyncCallInvoker.cpp new file mode 100644 index 000000000..9e007da64 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/src/SyncCallInvoker.cpp @@ -0,0 +1,94 @@ +#include "SyncCallInvoker.h" + +#include + +namespace rnaudioapi::node { + +namespace { + +napi_value noopDispatch(napi_env env, napi_callback_info /* info */) { + napi_value undefined; + napi_get_undefined(env, &undefined); + return undefined; +} + +} // namespace + +SyncCallInvoker::SyncCallInvoker() : mainThreadId_(std::this_thread::get_id()) {} + +SyncCallInvoker::~SyncCallInvoker() { + if (tsfn_ != nullptr) { + napi_release_threadsafe_function(tsfn_, napi_tsfn_release); + tsfn_ = nullptr; + } +} + +void SyncCallInvoker::initialize(napi_env env) { + env_ = env; + mainThreadId_ = std::this_thread::get_id(); + + napi_value resourceName; + napi_create_string_utf8(env, "SyncCallInvoker", NAPI_AUTO_LENGTH, &resourceName); + + napi_value noopCallback; + napi_create_function( + env, + "syncCallInvokerDispatch", + NAPI_AUTO_LENGTH, + noopDispatch, + nullptr, + &noopCallback); + + napi_create_threadsafe_function( + env, + noopCallback, + nullptr, + resourceName, + 0, + 1, + this, + nullptr, + this, + SyncCallInvoker::onMainThread, + &tsfn_); +} + +void SyncCallInvoker::setRuntime(facebook::jsi::Runtime *runtime) { + runtime_ = runtime; +} + +void SyncCallInvoker::onMainThread( + napi_env /* env */, + napi_value /* jsCallback */, + void *context, + void *data) { + auto *invoker = static_cast(context); + auto *callFunc = static_cast(data); + if (invoker == nullptr || invoker->runtime_ == nullptr || callFunc == nullptr) { + delete callFunc; + return; + } + + (*callFunc)(*invoker->runtime_); + delete callFunc; +} + +void SyncCallInvoker::invokeAsync(facebook::react::CallFunc &&func) noexcept { + if (runtime_ == nullptr) { + return; + } + + if (std::this_thread::get_id() == mainThreadId_ || tsfn_ == nullptr) { + func(*runtime_); + return; + } + + auto *callFunc = new facebook::react::CallFunc(std::move(func)); + napi_call_threadsafe_function(tsfn_, callFunc, napi_tsfn_blocking); +} + +void SyncCallInvoker::invokeSync(facebook::react::CallFunc &&func) { + invokeAsync(std::move(func)); +} + +} // namespace rnaudioapi::node diff --git a/packages/react-native-audio-api/wpt_tests/src/SyncCallInvoker.h b/packages/react-native-audio-api/wpt_tests/src/SyncCallInvoker.h new file mode 100644 index 000000000..6ac89494a --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/src/SyncCallInvoker.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include + +#include + +namespace rnaudioapi::node { + +class SyncCallInvoker final : public facebook::react::CallInvoker { + public: + SyncCallInvoker(); + ~SyncCallInvoker() override; + + void initialize(napi_env env); + void setRuntime(facebook::jsi::Runtime *runtime); + + void invokeAsync(facebook::react::CallFunc &&func) noexcept override; + void invokeSync(facebook::react::CallFunc &&func) override; + + private: + static void onMainThread(napi_env env, napi_value jsCallback, void *context, void *data); + + napi_env env_{nullptr}; + napi_threadsafe_function tsfn_{nullptr}; + std::thread::id mainThreadId_; + facebook::jsi::Runtime *runtime_{nullptr}; +}; + +} // namespace rnaudioapi::node diff --git a/packages/react-native-audio-api/wpt_tests/src/addon_init.cpp b/packages/react-native-audio-api/wpt_tests/src/addon_init.cpp new file mode 100644 index 000000000..9c676134c --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/src/addon_init.cpp @@ -0,0 +1,30 @@ +#include "jsi_install.h" + +#include + +namespace { + +napi_value install(napi_env env, napi_callback_info /* info */) { + return installUsingJsiBindings(env); +} + +napi_value createNativeModule(napi_env env) { + napi_value module; + napi_create_object(env, &module); + + napi_value installFn; + napi_create_function(env, "install", NAPI_AUTO_LENGTH, install, nullptr, &installFn); + napi_set_named_property(env, module, "install", installFn); + + return module; +} + +napi_value Init(napi_env env, napi_value exports) { + napi_value nativeModule = createNativeModule(env); + napi_set_named_property(env, exports, "nativeModule", nativeModule); + return exports; +} + +} // namespace + +NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) diff --git a/packages/react-native-audio-api/wpt_tests/src/jsi_install.cpp b/packages/react-native-audio-api/wpt_tests/src/jsi_install.cpp new file mode 100644 index 000000000..029677c5d --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/src/jsi_install.cpp @@ -0,0 +1,258 @@ +#include "jsi_install.h" + +#include "NodeJSRuntimeApi.h" +#include "SyncCallInvoker.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace { + +using audioapi::AudioBuffer; +using audioapi::AudioBufferHostObject; +using audioapi::AudioContextHostObject; +using audioapi::AudioEventHandlerRegistry; +using audioapi::AudioEventHandlerRegistryHostObject; +using audioapi::OfflineAudioContextHostObject; +using facebook::jsi::Function; +using facebook::jsi::JSError; +using facebook::jsi::Object; +using facebook::jsi::PropNameID; +using facebook::jsi::Runtime; +using facebook::jsi::String; +using facebook::jsi::Value; +using Microsoft::NodeApiJsi::makeNodeApiJsiRuntime; +using rnaudioapi::node::NodeJSRuntimeApi; +using rnaudioapi::node::SyncCallInvoker; +using RuntimeRegistry = ::RuntimeRegistry; + +struct JsiInstallState { + std::unique_ptr jsRuntimeApi; + std::unique_ptr runtime; + std::shared_ptr callInvoker; + std::shared_ptr eventRegistry; +}; + +std::mutex gInstallMutex; +std::unordered_map> gInstallStates; + +void cleanupInstallState(void *data) { + auto *env = reinterpret_cast(data); + std::lock_guard lock(gInstallMutex); + gInstallStates.erase(env); +} + +napi_value makeBoolean(napi_env env, bool value) { + napi_value result; + napi_get_boolean(env, value, &result); + return result; +} + +[[noreturn]] void throwTypeError(Runtime &runtime, const std::string &message) { + auto typeError = runtime.global().getPropertyAsFunction(runtime, "TypeError"); + auto error = typeError.callAsConstructor(runtime, String::createFromUtf8(runtime, message)); + throw JSError(runtime, std::move(error)); +} + +bool isNullOrUndefined(const Value &value) { + return value.isNull() || value.isUndefined(); +} + +void parseOfflineContextArgs( + Runtime &runtime, + const Value *args, + size_t count, + int &numberOfChannels, + size_t &length, + float &sampleRate) { + numberOfChannels = 1; + length = 0; + sampleRate = 0.0f; + + if (count >= 3 && args[0].isNumber() && args[1].isNumber() && args[2].isNumber()) { + numberOfChannels = static_cast(args[0].getNumber()); + length = static_cast(args[1].getNumber()); + sampleRate = static_cast(args[2].getNumber()); + return; + } + + if (count >= 2 && args[0].isNumber() && args[1].isNumber()) { + numberOfChannels = 1; + length = static_cast(args[0].getNumber()); + sampleRate = static_cast(args[1].getNumber()); + return; + } + + if (count >= 3 && isNullOrUndefined(args[0]) && args[1].isNumber() && args[2].isNumber()) { + numberOfChannels = 1; + length = static_cast(args[1].getNumber()); + sampleRate = static_cast(args[2].getNumber()); + return; + } + + throwTypeError( + runtime, + "createOfflineAudioContext expects at least (length, sampleRate) or " + "(numberOfChannels, length, sampleRate)."); +} + +void installOfflineBindings( + Runtime &runtime, + const std::shared_ptr &eventRegistry, + const std::shared_ptr &callInvoker) { + auto createOfflineAudioContext = Function::createFromHostFunction( + runtime, + PropNameID::forAscii(runtime, "createOfflineAudioContext"), + 3, + [eventRegistry, callInvoker]( + Runtime &rt, + const Value & /* thisValue */, + const Value *args, + size_t count) -> Value { + int numberOfChannels = 1; + size_t length = 0; + float sampleRate = 0.0f; + parseOfflineContextArgs( + rt, args, count, numberOfChannels, length, sampleRate); + + auto hostObject = std::make_shared( + numberOfChannels, + length, + sampleRate, + eventRegistry, + RuntimeRegistry{}, + &rt, + callInvoker); + + return Object::createFromHostObject(rt, hostObject); + }); + runtime.global().setProperty(runtime, "createOfflineAudioContext", createOfflineAudioContext); + + auto createAudioBuffer = Function::createFromHostFunction( + runtime, + PropNameID::forAscii(runtime, "createAudioBuffer"), + 3, + []( + Runtime &rt, + const Value & /* thisValue */, + const Value *args, + size_t count) -> Value { + if (count < 3 || !args[0].isNumber() || !args[1].isNumber() || !args[2].isNumber()) { + throwTypeError( + rt, + "createAudioBuffer(numberOfChannels, length, sampleRate) requires 3 numeric arguments."); + } + + const auto numberOfChannels = static_cast(args[0].getNumber()); + const auto length = static_cast(args[1].getNumber()); + const auto sampleRate = static_cast(args[2].getNumber()); + + auto audioBuffer = std::make_shared(length, numberOfChannels, sampleRate); + auto audioBufferHostObject = std::make_shared(audioBuffer); + return Object::createFromHostObject(rt, audioBufferHostObject); + }); + runtime.global().setProperty(runtime, "createAudioBuffer", createAudioBuffer); +} + +void installAudioContextBinding( + Runtime &runtime, + const std::shared_ptr &eventRegistry, + const std::shared_ptr &callInvoker) { + auto createAudioContext = Function::createFromHostFunction( + runtime, + PropNameID::forAscii(runtime, "createAudioContext"), + 2, + [eventRegistry, callInvoker]( + Runtime &rt, + const Value & /* thisValue */, + const Value *args, + size_t count) -> Value { + if (count < 1 || !args[0].isNumber()) { + throwTypeError(rt, "createAudioContext(sampleRate) requires a numeric sampleRate."); + } + + const auto sampleRate = static_cast(args[0].getNumber()); + auto hostObject = std::make_shared( + sampleRate, + eventRegistry, + RuntimeRegistry{}, + &rt, + callInvoker); + + return Object::createFromHostObject(rt, hostObject); + }); + + runtime.global().setProperty(runtime, "createAudioContext", createAudioContext); +} + +void installUnsupportedGlobal(Runtime &runtime, const char *name) { + auto fn = Function::createFromHostFunction( + runtime, + PropNameID::forAscii(runtime, name), + 0, + [name](Runtime &rt, const Value &, const Value *, size_t) -> Value { + throw JSError(rt, std::string(name) + "() is not available in Node phase-1 JSI bindings."); + }); + runtime.global().setProperty(runtime, name, std::move(fn)); +} + +void installAudioEventEmitter( + Runtime &runtime, + const std::shared_ptr &eventRegistry) { + auto eventEmitter = std::make_shared(eventRegistry); + runtime.global().setProperty( + runtime, + "AudioEventEmitter", + Object::createFromHostObject(runtime, eventEmitter)); +} + +} // namespace + +napi_value installUsingJsiBindings(napi_env env) { + try { + std::scoped_lock lock(gInstallMutex); + auto existing = gInstallStates.find(env); + if (existing != gInstallStates.end()) { + return makeBoolean(env, true); + } + + auto state = std::make_unique(); + state->jsRuntimeApi = std::make_unique(); + Microsoft::NodeApiJsi::JSRuntimeApi::setCurrent(state->jsRuntimeApi->api()); + state->runtime = makeNodeApiJsiRuntime(env, state->jsRuntimeApi->api(), [] {}); + state->callInvoker = std::make_shared(); + state->callInvoker->initialize(env); + state->callInvoker->setRuntime(state->runtime.get()); + state->eventRegistry = + std::make_shared(state->runtime.get(), state->callInvoker); + + installOfflineBindings(*state->runtime, state->eventRegistry, state->callInvoker); + installAudioContextBinding(*state->runtime, state->eventRegistry, state->callInvoker); + installUnsupportedGlobal(*state->runtime, "createAudioRecorder"); + installUnsupportedGlobal(*state->runtime, "createAudioDecoder"); + installUnsupportedGlobal(*state->runtime, "createAudioFileUtils"); + installUnsupportedGlobal(*state->runtime, "createAudioStretcher"); + installAudioEventEmitter(*state->runtime, state->eventRegistry); + + napi_add_env_cleanup_hook(env, cleanupInstallState, env); + gInstallStates.emplace(env, std::move(state)); + return makeBoolean(env, true); + } catch (const std::exception &error) { + napi_throw_error(env, nullptr, error.what()); + return nullptr; + } catch (...) { + napi_throw_error(env, nullptr, "Unexpected error while installing JSI bindings."); + return nullptr; + } +} diff --git a/packages/react-native-audio-api/wpt_tests/src/jsi_install.h b/packages/react-native-audio-api/wpt_tests/src/jsi_install.h new file mode 100644 index 000000000..d5847c33c --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/src/jsi_install.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +napi_value installUsingJsiBindings(napi_env env); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/META.yml b/packages/react-native-audio-api/wpt_tests/webaudio/META.yml new file mode 100644 index 000000000..735f0ebd3 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/META.yml @@ -0,0 +1,5 @@ +spec: https://webaudio.github.io/web-audio-api/ +suggested_reviewers: + - hoch + - padenot + - chrisguttandin diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/README.md b/packages/react-native-audio-api/wpt_tests/webaudio/README.md new file mode 100644 index 000000000..bcfe291ff --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/README.md @@ -0,0 +1,5 @@ +Our test suite is currently tracking the [editor's draft](https://webaudio.github.io/web-audio-api/) of the Web Audio API. + +The tests are arranged in subdirectories, corresponding to different +sections of the spec. So, for example, tests for the `DelayNode` are +in `the-audio-api/the-delaynode-interface`. diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/historical.html b/packages/react-native-audio-api/wpt_tests/webaudio/historical.html new file mode 100644 index 000000000..1f3146c39 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/historical.html @@ -0,0 +1,29 @@ + +Historical Web Audio API features + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/idlharness.https.window.js b/packages/react-native-audio-api/wpt_tests/webaudio/idlharness.https.window.js new file mode 100644 index 000000000..e941a75c2 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/idlharness.https.window.js @@ -0,0 +1,72 @@ +// META: script=/resources/WebIDLParser.js +// META: script=/resources/idlharness.js +// META: timeout=long + +// https://webaudio.github.io/web-audio-api/ + +'use strict'; + +idl_test( + ['webaudio'], + ['cssom', 'uievents', 'mediacapture-streams', 'html', 'dom'], + async idl_array => { + idl_array.add_untested_idls('interface SVGElement {};'); + + idl_array.add_objects({ + BaseAudioContext: [], + AudioContext: ['context'], + OfflineAudioContext: ['new OfflineAudioContext(1, 1, sample_rate)'], + OfflineAudioCompletionEvent: [ + 'new OfflineAudioCompletionEvent("", {renderedBuffer: buffer})' + ], + AudioBuffer: ['buffer'], + AudioNode: [], + AudioParam: ['new AudioBufferSourceNode(context).playbackRate'], + AudioScheduledSourceNode: [], + AnalyserNode: ['new AnalyserNode(context)'], + AudioBufferSourceNode: ['new AudioBufferSourceNode(context)'], + AudioDestinationNode: ['context.destination'], + AudioListener: ['context.listener'], + AudioProcessingEvent: [`new AudioProcessingEvent('', { + playbackTime: 0, inputBuffer: buffer, outputBuffer: buffer + })`], + BiquadFilterNode: ['new BiquadFilterNode(context)'], + ChannelMergerNode: ['new ChannelMergerNode(context)'], + ChannelSplitterNode: ['new ChannelSplitterNode(context)'], + ConstantSourceNode: ['new ConstantSourceNode(context)'], + ConvolverNode: ['new ConvolverNode(context)'], + DelayNode: ['new DelayNode(context)'], + DynamicsCompressorNode: ['new DynamicsCompressorNode(context)'], + GainNode: ['new GainNode(context)'], + IIRFilterNode: [ + 'new IIRFilterNode(context, {feedforward: [1], feedback: [1]})' + ], + MediaElementAudioSourceNode: [ + 'new MediaElementAudioSourceNode(context, {mediaElement: new Audio})' + ], + MediaStreamAudioDestinationNode: [ + 'new MediaStreamAudioDestinationNode(context)' + ], + MediaStreamAudioSourceNode: [], + MediaStreamTrackAudioSourceNode: [], + OscillatorNode: ['new OscillatorNode(context)'], + PannerNode: ['new PannerNode(context)'], + PeriodicWave: ['new PeriodicWave(context)'], + ScriptProcessorNode: ['context.createScriptProcessor()'], + StereoPannerNode: ['new StereoPannerNode(context)'], + WaveShaperNode: ['new WaveShaperNode(context)'], + AudioWorklet: ['context.audioWorklet'], + AudioWorkletGlobalScope: [], + AudioParamMap: ['worklet_node.parameters'], + AudioWorkletNode: ['worklet_node'], + AudioWorkletProcessor: [], + }); + + self.sample_rate = 44100; + self.context = new AudioContext; + self.buffer = new AudioBuffer({length: 1, sampleRate: sample_rate}); + await context.audioWorklet.addModule( + 'the-audio-api/the-audioworklet-interface/processors/dummy-processor.js'); + self.worklet_node = new AudioWorkletNode(context, 'dummy'); + } +); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/js/buffer-loader.js b/packages/react-native-audio-api/wpt_tests/webaudio/js/buffer-loader.js new file mode 100644 index 000000000..453dc4a52 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/js/buffer-loader.js @@ -0,0 +1,44 @@ +/* Taken from + https://raw.github.com/WebKit/webkit/master/LayoutTests/webaudio/resources/buffer-loader.js */ + +function BufferLoader(context, urlList, callback) { + this.context = context; + this.urlList = urlList; + this.onload = callback; + this.bufferList = new Array(); + this.loadCount = 0; +} + +BufferLoader.prototype.loadBuffer = function(url, index) { + // Load buffer asynchronously + var request = new XMLHttpRequest(); + request.open("GET", url, true); + request.responseType = "arraybuffer"; + + var loader = this; + + request.onload = function() { + loader.context.decodeAudioData(request.response, decodeSuccessCallback, decodeErrorCallback); + }; + + request.onerror = function() { + alert('BufferLoader: XHR error'); + }; + + var decodeSuccessCallback = function(buffer) { + loader.bufferList[index] = buffer; + if (++loader.loadCount == loader.urlList.length) + loader.onload(loader.bufferList); + }; + + var decodeErrorCallback = function() { + alert('decodeErrorCallback: decode error'); + }; + + request.send(); +} + +BufferLoader.prototype.load = function() { + for (var i = 0; i < this.urlList.length; ++i) + this.loadBuffer(this.urlList[i], i); +} diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/js/helpers.js b/packages/react-native-audio-api/wpt_tests/webaudio/js/helpers.js new file mode 100644 index 000000000..413c72051 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/js/helpers.js @@ -0,0 +1,250 @@ +/* + Returns an array (typed or not), of the passed array with removed trailing and ending + zero-valued elements + */ +function trimEmptyElements(array) { + var start = 0; + var end = array.length; + + while (start < array.length) { + if (array[start] !== 0) { + break; + } + start++; + } + + while (end > 0) { + end--; + if (array[end] !== 0) { + break; + } + } + return array.subarray(start, end); +} + + +function fuzzyCompare(a, b) { + return Math.abs(a - b) < 9e-3; +} + +function compareChannels(buf1, buf2, + /*optional*/ length, + /*optional*/ sourceOffset, + /*optional*/ destOffset, + /*optional*/ skipLengthCheck) { + if (!skipLengthCheck) { + assert_equals(buf1.length, buf2.length, "Channels must have the same length"); + } + sourceOffset = sourceOffset || 0; + destOffset = destOffset || 0; + if (length == undefined) { + length = buf1.length - sourceOffset; + } + var difference = 0; + var maxDifference = 0; + var firstBadIndex = -1; + for (var i = 0; i < length; ++i) { + if (!fuzzyCompare(buf1[i + sourceOffset], buf2[i + destOffset])) { + difference++; + maxDifference = Math.max(maxDifference, Math.abs(buf1[i + sourceOffset] - buf2[i + destOffset])); + if (firstBadIndex == -1) { + firstBadIndex = i; + } + } + }; + + assert_equals(difference, 0, "maxDifference: " + maxDifference + + ", first bad index: " + firstBadIndex + " with test-data offset " + + sourceOffset + " and expected-data offset " + destOffset + + "; corresponding values " + buf1[firstBadIndex + sourceOffset] + " and " + + buf2[firstBadIndex + destOffset] + " --- differences"); +} + +function compareBuffers(got, expected) { + if (got.numberOfChannels != expected.numberOfChannels) { + assert_equals(got.numberOfChannels, expected.numberOfChannels, + "Correct number of buffer channels"); + return; + } + if (got.length != expected.length) { + assert_equals(got.length, expected.length, + "Correct buffer length"); + return; + } + if (got.sampleRate != expected.sampleRate) { + assert_equals(got.sampleRate, expected.sampleRate, + "Correct sample rate"); + return; + } + + for (var i = 0; i < got.numberOfChannels; ++i) { + compareChannels(got.getChannelData(i), expected.getChannelData(i), + got.length, 0, 0, true); + } +} + +/** + * This function assumes that the test is a "single page test" [0], and defines a + * single gTest variable with the following properties and methods: + * + * + numberOfChannels: optional property which specifies the number of channels + * in the output. The default value is 2. + * + createGraph: mandatory method which takes a context object and does + * everything needed in order to set up the Web Audio graph. + * This function returns the node to be inspected. + * + createGraphAsync: async version of createGraph. This function takes + * a callback which should be called with an argument + * set to the node to be inspected when the callee is + * ready to proceed with the test. Either this function + * or createGraph must be provided. + * + createExpectedBuffers: optional method which takes a context object and + * returns either one expected buffer or an array of + * them, designating what is expected to be observed + * in the output. If omitted, the output is expected + * to be silence. All buffers must have the same + * length, which must be a bufferSize supported by + * ScriptProcessorNode. This function is guaranteed + * to be called before createGraph. + * + length: property equal to the total number of frames which we are waiting + * to see in the output, mandatory if createExpectedBuffers is not + * provided, in which case it must be a bufferSize supported by + * ScriptProcessorNode (256, 512, 1024, 2048, 4096, 8192, or 16384). + * If createExpectedBuffers is provided then this must be equal to + * the number of expected buffers * the expected buffer length. + * + * + skipOfflineContextTests: optional. when true, skips running tests on an offline + * context by circumventing testOnOfflineContext. + * + * [0]: https://web-platform-tests.org/writing-tests/testharness-api.html#single-page-tests + */ +function runTest(name) +{ + function runTestFunction () { + if (!gTest.numberOfChannels) { + gTest.numberOfChannels = 2; // default + } + + var testLength; + + function runTestOnContext(context, callback, testOutput) { + if (!gTest.createExpectedBuffers) { + // Assume that the output is silence + var expectedBuffers = getEmptyBuffer(context, gTest.length); + } else { + var expectedBuffers = gTest.createExpectedBuffers(context); + } + if (!(expectedBuffers instanceof Array)) { + expectedBuffers = [expectedBuffers]; + } + var expectedFrames = 0; + for (var i = 0; i < expectedBuffers.length; ++i) { + assert_equals(expectedBuffers[i].numberOfChannels, gTest.numberOfChannels, + "Correct number of channels for expected buffer " + i); + expectedFrames += expectedBuffers[i].length; + } + if (gTest.length && gTest.createExpectedBuffers) { + assert_equals(expectedFrames, + gTest.length, "Correct number of expected frames"); + } + + if (gTest.createGraphAsync) { + gTest.createGraphAsync(context, function(nodeToInspect) { + testOutput(nodeToInspect, expectedBuffers, callback); + }); + } else { + testOutput(gTest.createGraph(context), expectedBuffers, callback); + } + } + + function testOnNormalContext(callback) { + function testOutput(nodeToInspect, expectedBuffers, callback) { + testLength = 0; + var sp = context.createScriptProcessor(expectedBuffers[0].length, gTest.numberOfChannels, 1); + nodeToInspect.connect(sp).connect(context.destination); + sp.onaudioprocess = function(e) { + var expectedBuffer = expectedBuffers.shift(); + testLength += expectedBuffer.length; + compareBuffers(e.inputBuffer, expectedBuffer); + if (expectedBuffers.length == 0) { + sp.onaudioprocess = null; + callback(); + } + }; + } + var context = new AudioContext(); + runTestOnContext(context, callback, testOutput); + } + + function testOnOfflineContext(callback, sampleRate) { + function testOutput(nodeToInspect, expectedBuffers, callback) { + nodeToInspect.connect(context.destination); + context.oncomplete = function(e) { + var samplesSeen = 0; + while (expectedBuffers.length) { + var expectedBuffer = expectedBuffers.shift(); + assert_equals(e.renderedBuffer.numberOfChannels, expectedBuffer.numberOfChannels, + "Correct number of input buffer channels"); + for (var i = 0; i < e.renderedBuffer.numberOfChannels; ++i) { + compareChannels(e.renderedBuffer.getChannelData(i), + expectedBuffer.getChannelData(i), + expectedBuffer.length, + samplesSeen, + undefined, + true); + } + samplesSeen += expectedBuffer.length; + } + callback(); + }; + context.startRendering(); + } + + var context = new OfflineAudioContext(gTest.numberOfChannels, testLength, sampleRate); + runTestOnContext(context, callback, testOutput); + } + + testOnNormalContext(function() { + if (!gTest.skipOfflineContextTests) { + testOnOfflineContext(function() { + testOnOfflineContext(done, 44100); + }, 48000); + } else { + done(); + } + }); + }; + + runTestFunction(); +} + +// Simpler than audit.js, but still logs the message. Requires +// `setup("explicit_done": true)` if testing code that runs after the "load" +// event. +function equals(a, b, msg) { + test(function() { + assert_equals(a, b); + }, msg); +} +function is_true(a, msg) { + test(function() { + assert_true(a); + }, msg); +} + +// This allows writing AudioWorkletProcessor code in the same file as the rest +// of the test, for quick one off AudioWorkletProcessor testing. +function URLFromScriptsElements(ids) +{ + var scriptTexts = []; + for (let id of ids) { + + const e = document.querySelector("script#"+id) + if (!e) { + throw id+" is not the id of a + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/media-playback-while-not-visible-permission-policy/resources/audiocontext-frame.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/media-playback-while-not-visible-permission-policy/resources/audiocontext-frame.html new file mode 100644 index 000000000..66d96c7df --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/media-playback-while-not-visible-permission-policy/resources/audiocontext-frame.html @@ -0,0 +1,36 @@ + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/media-playback-while-not-visible-permission-policy/resources/intermediate-frame.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/media-playback-while-not-visible-permission-policy/resources/intermediate-frame.html new file mode 100644 index 000000000..d92042972 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/media-playback-while-not-visible-permission-policy/resources/intermediate-frame.html @@ -0,0 +1,29 @@ + + + + Intermediate frame embedding a nested AudioContext iframe + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/media-playback-while-not-visible-permission-policy/resources/media-playback-while-not-visible-utils.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/media-playback-while-not-visible-permission-policy/resources/media-playback-while-not-visible-utils.js new file mode 100644 index 000000000..27b8a9721 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/media-playback-while-not-visible-permission-policy/resources/media-playback-while-not-visible-utils.js @@ -0,0 +1,136 @@ +// Shared helpers for the media-playback-while-not-visible permission policy +// tests. The same helpers drive both the same-origin and cross-origin +// scenarios; the only difference between the two is the origin of the iframe +// that hosts the AudioContext, which is passed in as `base` (a URL prefix to +// the resources/ directory on the desired origin). + +// Returns a promise that resolves when the iframe's AudioContext emits a +// 'statechange' event. The promise resolves with the new state of the +// AudioContext, or with 'no state change' if no event fires within `timeout` +// milliseconds. The event listener is removed once the promise settles. +// Callers that expect no state change can pass a shorter `timeout` to avoid +// waiting the full default duration on every negative assertion. +function expectIframeAudioContextStateChangeEvent(test, timeout = 2000) { + return new Promise(resolve => { + function expectStateChangeEvent(event) { + if (event.data.operation !== 'statechange') { + return; + } + window.removeEventListener('message', expectStateChangeEvent); + resolve(event.data.value); + } + + window.addEventListener('message', expectStateChangeEvent); + test.step_timeout(() => { + window.removeEventListener('message', expectStateChangeEvent); + resolve('no state change'); + }, timeout); + }); +} + +// Sends a message to the iframe to query the state of the AudioContext and +// returns a promise that resolves with the state of the AudioContext. The +// event listener is removed after the promise resolves. +function queryAudioContextState(iframe) { + return new Promise(resolve => { + window.addEventListener( + 'message', function expectStateQueryResponse(event) { + if (event.data.operation !== 'getState') { + return; + } + window.removeEventListener('message', expectStateQueryResponse); + resolve(event.data.value); + }); + iframe.contentWindow.postMessage('getState', '*'); + }); +} + +// Sends a message to the iframe with a command that should be performed on +// the AudioContext. Returns a promise that resolves when the operation is +// completed. The event listener is removed after the promise resolves. +function sendCommandToAudioContext(iframe, command) { + return new Promise(resolve => { + window.addEventListener('message', function expectCommandResponse(event) { + if (event.data.operation !== command) { + return; + } + window.removeEventListener('message', expectCommandResponse); + resolve(event.data.value); + }); + iframe.contentWindow.postMessage(command, '*'); + }); +} + +// Drives the iframe's AudioContext into `expected_initial_state` ('running' or +// 'suspended'). Returns a promise that resolves with the resulting state. +async function setUpIframeAudioContextInitialState(t, iframe, + expected_initial_state) { + const initial_state = await queryAudioContextState(iframe); + if (initial_state === expected_initial_state || initial_state === 'closed') { + return initial_state; + } + + const statechange_promise = expectIframeAudioContextStateChangeEvent(t); + if (expected_initial_state === 'running') { + await sendCommandToAudioContext(iframe, 'resume'); + } else if (expected_initial_state === 'suspended') { + await sendCommandToAudioContext(iframe, 'suspend'); + } + + return statechange_promise; +} + +function hideFrame(iframe, type) { + if (type === 'display') { + iframe.style.setProperty('display', 'none'); + } else if (type === 'visibility') { + iframe.style.setProperty('visibility', 'hidden'); + } else if (type === 'zero-size') { + iframe.style.setProperty('width', '0'); + iframe.style.setProperty('height', '0'); + } +} + +function showFrame(iframe, type) { + if (type === 'display') { + iframe.style.setProperty('display', 'block'); + } else if (type === 'visibility') { + iframe.style.setProperty('visibility', 'visible'); + } else if (type === 'zero-size') { + iframe.style.removeProperty('width'); + iframe.style.removeProperty('height'); + } +} + +// Creates an iframe that hosts an AudioContext and waits for it to reach the +// 'running' state. `base` is the URL prefix (including trailing slash) to the +// resources/ directory on the desired origin; using the alternate-host base +// produces a genuine cross-origin (out-of-process) iframe. If `frameType` is +// 'nested', an intermediate iframe is inserted between the test page and the +// AudioContext frame, so the test page and the AudioContext frame are always +// separated by at least one frame boundary on origin `base`. +async function createIframe(t, frameType, base) { + if (document.readyState !== 'complete') { + await new Promise(resolve => window.addEventListener('load', resolve)); + } + + const running_state_transition_promise = + expectIframeAudioContextStateChangeEvent(t); + + const iframe = document.createElement('iframe'); + if (frameType === 'nested') { + iframe.id = 'intermediate-frame'; + iframe.src = base + 'intermediate-frame.html'; + } else { + iframe.id = 'audio-context-frame'; + iframe.allow = 'media-playback-while-not-visible \'none\'; autoplay *'; + iframe.src = base + 'audiocontext-frame.html'; + } + + document.body.appendChild(iframe); + await new Promise(resolve => iframe.addEventListener('load', resolve)); + t.add_cleanup(() => iframe.remove()); + + assert_equals(await running_state_transition_promise, 'running'); + return iframe; +} diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/media-playback-while-not-visible-permission-policy/resume-while-hidden.tentative.sub.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/media-playback-while-not-visible-permission-policy/resume-while-hidden.tentative.sub.html new file mode 100644 index 000000000..ddf7ac0bd --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/media-playback-while-not-visible-permission-policy/resume-while-hidden.tentative.sub.html @@ -0,0 +1,76 @@ + + + + resume() on a suspended AudioContext in a hidden iframe rejects and interrupts + (media-playback-while-not-visible permission policy) + + + + + + + + + + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/media-playback-while-not-visible-permission-policy/suspended-hide-show.tentative.sub.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/media-playback-while-not-visible-permission-policy/suspended-hide-show.tentative.sub.html new file mode 100644 index 000000000..f49d7ef5b --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/media-playback-while-not-visible-permission-policy/suspended-hide-show.tentative.sub.html @@ -0,0 +1,60 @@ + + + + Suspended AudioContext does not change state when its iframe is hidden/shown + (media-playback-while-not-visible permission policy) + + + + + + + + + + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/media-playback-while-not-visible-permission-policy/viewport.tentative.sub.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/media-playback-while-not-visible-permission-policy/viewport.tentative.sub.html new file mode 100644 index 000000000..da250ce50 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/media-playback-while-not-visible-permission-policy/viewport.tentative.sub.html @@ -0,0 +1,66 @@ + + + + AudioContext is not interrupted when its iframe is merely scrolled out of view + (media-playback-while-not-visible permission policy) + + + + + + + + +
+ +
+
+ + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/processing-model/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/processing-model/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/processing-model/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/processing-model/cycle-without-delay.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/processing-model/cycle-without-delay.html new file mode 100644 index 000000000..cab0f6ca8 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/processing-model/cycle-without-delay.html @@ -0,0 +1,36 @@ + + + + Cycles without DelayNode in audio node graph + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/processing-model/delay-time-clamping.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/processing-model/delay-time-clamping.html new file mode 100644 index 000000000..fa010df3c --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/processing-model/delay-time-clamping.html @@ -0,0 +1,43 @@ + + + + Delay time clamping in cycles + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/processing-model/feedback-delay-time.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/processing-model/feedback-delay-time.html new file mode 100644 index 000000000..96c2eb065 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/processing-model/feedback-delay-time.html @@ -0,0 +1,42 @@ + + + + Feedback cycle with delay in audio node graph + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/rendersizehint-smoke-tests.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/rendersizehint-smoke-tests.https.html new file mode 100644 index 000000000..952b679be --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/rendersizehint-smoke-tests.https.html @@ -0,0 +1,123 @@ + +Smoke tests for standard nodes with renderSizeHint + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/.gitkeep b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/analysernode-rendersizehint.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/analysernode-rendersizehint.https.html new file mode 100644 index 000000000..60e8b46ec --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/analysernode-rendersizehint.https.html @@ -0,0 +1,25 @@ + +Test AnalyserNode with renderSizeHint + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/ctor-analyser.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/ctor-analyser.html new file mode 100644 index 000000000..a9aa48315 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/ctor-analyser.html @@ -0,0 +1,183 @@ + + + + + Test Constructor: AnalyserNode + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/realtimeanalyser-basic.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/realtimeanalyser-basic.html new file mode 100644 index 000000000..87e354326 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/realtimeanalyser-basic.html @@ -0,0 +1,48 @@ + + + + + Basic AnalyserNode test + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/realtimeanalyser-fft-scaling.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/realtimeanalyser-fft-scaling.html new file mode 100644 index 000000000..7ee63bf76 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/realtimeanalyser-fft-scaling.html @@ -0,0 +1,105 @@ + + + + + realtimeanalyser-fft-scaling.html + + + + + +
+
+ + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/realtimeanalyser-fft-sizing.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/realtimeanalyser-fft-sizing.html new file mode 100644 index 000000000..7ee6a2237 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/realtimeanalyser-fft-sizing.html @@ -0,0 +1,54 @@ + + + + + realtimeanalyser-fft-sizing.html + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/test-analyser-gain.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/test-analyser-gain.html new file mode 100644 index 000000000..dff51a74c --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/test-analyser-gain.html @@ -0,0 +1,50 @@ + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/test-analyser-minimum.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/test-analyser-minimum.html new file mode 100644 index 000000000..ab0fe6b2d --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/test-analyser-minimum.html @@ -0,0 +1,43 @@ + + + + + Test AnalyserNode when the input is silent + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/test-analyser-output.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/test-analyser-output.html new file mode 100644 index 000000000..7d59e67b4 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/test-analyser-output.html @@ -0,0 +1,54 @@ + +Test AnalyserNode passes input to output unmodified + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/test-analyser-resume-after-suspended.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/test-analyser-resume-after-suspended.html new file mode 100644 index 000000000..82b17faa5 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/test-analyser-resume-after-suspended.html @@ -0,0 +1,106 @@ + + +AnalyzerNode resumed after suspended + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/test-analyser-scale.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/test-analyser-scale.html new file mode 100644 index 000000000..904b14bed --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/test-analyser-scale.html @@ -0,0 +1,51 @@ + + + + + Test AnalyserNode when the input is scaled + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/test-analysernode.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/test-analysernode.html new file mode 100644 index 000000000..e8325388d --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-analysernode-interface/test-analysernode.html @@ -0,0 +1,237 @@ + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/.gitkeep b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/acquire-the-content.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/acquire-the-content.html new file mode 100644 index 000000000..70f5d8e32 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/acquire-the-content.html @@ -0,0 +1,85 @@ + + +Test for AudioBuffer's "acquire the content" operation + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-copy-channel.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-copy-channel.html new file mode 100644 index 000000000..c0cd49d32 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-copy-channel.html @@ -0,0 +1,330 @@ + + + + + Test Basic Functionality of AudioBuffer.copyFromChannel and + AudioBuffer.copyToChannel + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-getChannelData.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-getChannelData.html new file mode 100644 index 000000000..612a91cf4 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-getChannelData.html @@ -0,0 +1,66 @@ + + + + + Test AudioBuffer.getChannelData() Returns the Same Object + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-reuse.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-reuse.html new file mode 100644 index 000000000..dabe323cb --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-reuse.html @@ -0,0 +1,36 @@ + + +AudioBuffer can be reused between AudioBufferSourceNodes + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer.html new file mode 100644 index 000000000..115e8aff1 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer.html @@ -0,0 +1,65 @@ + + + + AudioBuffer API Test + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/crashtests/copyFromChannel-bufferOffset-1.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/crashtests/copyFromChannel-bufferOffset-1.html new file mode 100644 index 000000000..564317f7d --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/crashtests/copyFromChannel-bufferOffset-1.html @@ -0,0 +1,11 @@ + + + Test large bufferOffset in copyFromChannel() + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/crashtests/copyToChannel-bufferOffset-1.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/crashtests/copyToChannel-bufferOffset-1.html new file mode 100644 index 000000000..999925a98 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/crashtests/copyToChannel-bufferOffset-1.html @@ -0,0 +1,10 @@ + + + Test large bufferOffset in copyToChannel() + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/ctor-audiobuffer.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/ctor-audiobuffer.html new file mode 100644 index 000000000..fbe6e42e3 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffer-interface/ctor-audiobuffer.html @@ -0,0 +1,236 @@ + + + + + Test Constructor: AudioBuffer + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/.gitkeep b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/active-processing.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/active-processing.https.html new file mode 100644 index 000000000..0d4b2e1fc --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/active-processing.https.html @@ -0,0 +1,84 @@ + + + + + Test Active Processing for AudioBufferSourceNode + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-basic.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-basic.html new file mode 100644 index 000000000..6ce7eb0c1 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-basic.html @@ -0,0 +1,37 @@ + + + + + Basic Test of AudioBufferSourceNode + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-channels.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-channels.html new file mode 100644 index 000000000..a6aef1362 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-channels.html @@ -0,0 +1,81 @@ + + + + audiobuffersource-channels.html + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-duration-loop-playbackrate.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-duration-loop-playbackrate.html new file mode 100644 index 000000000..048fc6744 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-duration-loop-playbackrate.html @@ -0,0 +1,223 @@ + + + + + + Test AudioBufferSourceNode Looping Duration With PlaybackRate + + + + + + + + + + + \ No newline at end of file diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-duration-loop.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-duration-loop.html new file mode 100644 index 000000000..fc2b55bce --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-duration-loop.html @@ -0,0 +1,53 @@ + + + + + Test AudioBufferSourceNode With Looping And Duration + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-ended.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-ended.html new file mode 100644 index 000000000..b9922f61e --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-ended.html @@ -0,0 +1,40 @@ + + + + + audiobuffersource-ended.html + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-grain.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-grain.html new file mode 100644 index 000000000..f554304a2 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-grain.html @@ -0,0 +1,71 @@ + + + + + Test Start Grain with Delayed Buffer Setting + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-loop-short-duration.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-loop-short-duration.html new file mode 100644 index 000000000..82271fbe5 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-loop-short-duration.html @@ -0,0 +1,46 @@ + + + + + audiobuffersource-loop-short-duration.html + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-multi-channels.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-multi-channels.html new file mode 100644 index 000000000..d830070d6 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-multi-channels.html @@ -0,0 +1,58 @@ + + + + + Test AudioBufferSourceNode supports 5.1 channel playback + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-null.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-null.html new file mode 100644 index 000000000..c0909deb0 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-null.html @@ -0,0 +1,46 @@ + + + + + Test ABSN Outputs Silence if buffer is null + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-one-sample-loop.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-one-sample-loop.html new file mode 100644 index 000000000..af1454a5a --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-one-sample-loop.html @@ -0,0 +1,47 @@ + + + + + Test AudioBufferSourceNode With Looping a Single-Sample Buffer + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-playbackrate-dynamic-direction.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-playbackrate-dynamic-direction.html new file mode 100644 index 000000000..1cf320da6 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-playbackrate-dynamic-direction.html @@ -0,0 +1,71 @@ + + + +AudioBufferSourceNode Dynamic PlaybackRate Direction + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-playbackrate-negative.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-playbackrate-negative.html new file mode 100644 index 000000000..f6083299c --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-playbackrate-negative.html @@ -0,0 +1,278 @@ + + + + + AudioBufferSourceNode: Negative PlaybackRate Edge Cases + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-playbackrate-zero.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-playbackrate-zero.html new file mode 100644 index 000000000..c8bcbb61d --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-playbackrate-zero.html @@ -0,0 +1,110 @@ + + + + audiobuffersource-playbackrate-zero.html + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-start-null-buffer.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-start-null-buffer.html new file mode 100644 index 000000000..7edc6e392 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-start-null-buffer.html @@ -0,0 +1,47 @@ + +AudioBufferSourceNode: start() with null buffer + + + \ No newline at end of file diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-start.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-start.html new file mode 100644 index 000000000..bfd62b482 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-start.html @@ -0,0 +1,174 @@ + + + + + audiobuffersource-start.html + + + + + + + + + + \ No newline at end of file diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiosource-onended.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiosource-onended.html new file mode 100644 index 000000000..acaaf36a9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiosource-onended.html @@ -0,0 +1,132 @@ + + + + + Test Onended Event Listener for AudioBufferSourceNode and OscillatorNode + + + + + + + + \ No newline at end of file diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiosource-time-limits.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiosource-time-limits.html new file mode 100644 index 000000000..ea3c67f01 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiosource-time-limits.html @@ -0,0 +1,61 @@ + + + + + Test Scheduled Sources with Huge Time Limits + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/buffer-resampling.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/buffer-resampling.html new file mode 100644 index 000000000..394d8e382 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/buffer-resampling.html @@ -0,0 +1,90 @@ + + + + Test Extrapolation at end of AudibBuffer in an AudioBufferSourceNode + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/ctor-audiobuffersource.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/ctor-audiobuffersource.html new file mode 100644 index 000000000..c1c320345 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/ctor-audiobuffersource.html @@ -0,0 +1,116 @@ + + + + + Test Constructor: AudioBufferSource + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/looped-constant-buffer.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/looped-constant-buffer.html new file mode 100644 index 000000000..0c45b8c45 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/looped-constant-buffer.html @@ -0,0 +1,45 @@ + + + + + Looped AudioBufferSourceNode Keeps Rendering + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/note-grain-on-play.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/note-grain-on-play.html new file mode 100644 index 000000000..453626aa4 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/note-grain-on-play.html @@ -0,0 +1,93 @@ + + + + + note-grain-on-play.html + + + + + + + +
+
+ + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/note-grain-on-timing.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/note-grain-on-timing.html new file mode 100644 index 000000000..0db297b42 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/note-grain-on-timing.html @@ -0,0 +1,47 @@ + + + + + note-grain-on-timing.html + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/resources/audiobuffersource-multi-channels-expected.wav b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/resources/audiobuffersource-multi-channels-expected.wav new file mode 100644 index 000000000..ab9d5fe5a Binary files /dev/null and b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/resources/audiobuffersource-multi-channels-expected.wav differ diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sample-accurate-scheduling.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sample-accurate-scheduling.html new file mode 100644 index 000000000..fd244e8a5 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sample-accurate-scheduling.html @@ -0,0 +1,109 @@ + + + + + + sample-accurate-scheduling.html + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html new file mode 100644 index 000000000..052afde71 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html @@ -0,0 +1,133 @@ + + + + + Test Sub-Sample Accurate Stitching of ABSNs + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-scheduling.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-scheduling.html new file mode 100644 index 000000000..8c627f90f --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-scheduling.html @@ -0,0 +1,423 @@ + + + + + Test Sub-Sample Accurate Scheduling for ABSN + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/.gitkeep b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-detached-execution-context.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-detached-execution-context.html new file mode 100644 index 000000000..a83fa1dbe --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-detached-execution-context.html @@ -0,0 +1,31 @@ + + + + + Testing behavior of AudioContext after execution context is detached + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-getoutputtimestamp-cross-realm.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-getoutputtimestamp-cross-realm.html new file mode 100644 index 000000000..5889faf7c --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-getoutputtimestamp-cross-realm.html @@ -0,0 +1,32 @@ + + + + + Testing AudioContext.getOutputTimestamp() method (cross-realm) + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-getoutputtimestamp.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-getoutputtimestamp.html new file mode 100644 index 000000000..952f38b1e --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-getoutputtimestamp.html @@ -0,0 +1,33 @@ + + + + + Testing AudioContext.getOutputTimestamp() method + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-not-fully-active.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-not-fully-active.html new file mode 100644 index 000000000..e4f6001ed --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-not-fully-active.html @@ -0,0 +1,94 @@ + +Test AudioContext construction when document is not fully active + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-playbackstats.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-playbackstats.html new file mode 100644 index 000000000..c50b120f3 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-playbackstats.html @@ -0,0 +1,144 @@ + + + + Testing AudioContext.playbackStats attribute + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-playoutstats.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-playoutstats.html new file mode 100644 index 000000000..9096d185a --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-playoutstats.html @@ -0,0 +1,144 @@ + + + + Testing AudioContext.playoutStats attribute + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-rendersizehint.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-rendersizehint.html new file mode 100644 index 000000000..711066d10 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-rendersizehint.html @@ -0,0 +1,8 @@ + +Test AudioContextOptions renderSizeHint + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-sinkid-constructor.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-sinkid-constructor.https.html new file mode 100644 index 000000000..a4f742068 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-sinkid-constructor.https.html @@ -0,0 +1,122 @@ + + +Test AudioContext constructor with sinkId options + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-sinkid-setsinkid.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-sinkid-setsinkid.https.html new file mode 100644 index 000000000..c72619c87 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-sinkid-setsinkid.https.html @@ -0,0 +1,135 @@ + + +Test AudioContext.setSinkId() method + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-sinkid-state-change.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-sinkid-state-change.https.html new file mode 100644 index 000000000..f59c4b2db --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-sinkid-state-change.https.html @@ -0,0 +1,126 @@ + + +Test AudioContext.setSinkId() state change + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-state-change-after-close.http.window.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-state-change-after-close.http.window.js new file mode 100644 index 000000000..eccb0d172 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-state-change-after-close.http.window.js @@ -0,0 +1,28 @@ +'use strict'; + +promise_test(async t => { + let audioContext = new AudioContext(); + await new Promise((resolve) => (audioContext.onstatechange = resolve)); + await audioContext.close(); + return promise_rejects_dom( + t, 'InvalidStateError', audioContext.close(), + 'A closed AudioContext should reject calls to close'); +}, 'Call close on a closed AudioContext'); + +promise_test(async t => { + let audioContext = new AudioContext(); + await new Promise((resolve) => (audioContext.onstatechange = resolve)); + await audioContext.close(); + return promise_rejects_dom( + t, 'InvalidStateError', audioContext.resume(), + 'A closed AudioContext should reject calls to resume'); +}, 'Call resume on a closed AudioContext'); + +promise_test(async t => { + let audioContext = new AudioContext(); + await new Promise((resolve) => (audioContext.onstatechange = resolve)); + await audioContext.close(); + return promise_rejects_dom( + t, 'InvalidStateError', audioContext.suspend(), + 'A closed AudioContext should reject calls to suspend'); +}, 'Call suspend on a closed AudioContext'); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-suspend-resume-close.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-suspend-resume-close.html new file mode 100644 index 000000000..c011f336d --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-suspend-resume-close.html @@ -0,0 +1,406 @@ + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-suspend-resume.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-suspend-resume.html new file mode 100644 index 000000000..a38183972 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-suspend-resume.html @@ -0,0 +1,106 @@ + + + + + Test AudioContext.suspend() and AudioContext.resume() + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontextoptions.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontextoptions.html new file mode 100644 index 000000000..af2a299bd --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontextoptions.html @@ -0,0 +1,238 @@ + + + + + Test AudioContextOptions + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/constructor-allowed-to-start.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/constructor-allowed-to-start.html new file mode 100644 index 000000000..f866b5f7a --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/constructor-allowed-to-start.html @@ -0,0 +1,25 @@ + +AudioContext state around "allowed to start" in constructor + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/context-time-monotonic-on-setsinkid.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/context-time-monotonic-on-setsinkid.https.html new file mode 100644 index 000000000..e9c2b39cc --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/context-time-monotonic-on-setsinkid.https.html @@ -0,0 +1,90 @@ + + + +currentTime and getOutputTimestamp().contextTime after setSinkId + + + + + + + + \ No newline at end of file diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/crashtests/currentTime-after-discard.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/crashtests/currentTime-after-discard.html new file mode 100644 index 000000000..8c74bd0aa --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/crashtests/currentTime-after-discard.html @@ -0,0 +1,14 @@ + + + + Test currentTime after browsing context discard + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/processing-after-resume.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/processing-after-resume.https.html new file mode 100644 index 000000000..e000ab124 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/processing-after-resume.https.html @@ -0,0 +1,55 @@ + +Test consistency of processing after resume() + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/promise-methods-after-discard.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/promise-methods-after-discard.html new file mode 100644 index 000000000..2fb3c5a50 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/promise-methods-after-discard.html @@ -0,0 +1,28 @@ + +Test for rejected promises from methods on an AudioContext in a + discarded browsing context + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/resources/not-fully-active-helper.sub.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/resources/not-fully-active-helper.sub.html new file mode 100644 index 000000000..2654a2a50 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/resources/not-fully-active-helper.sub.html @@ -0,0 +1,22 @@ + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/suspend-after-construct.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/suspend-after-construct.html new file mode 100644 index 000000000..596a825c3 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/suspend-after-construct.html @@ -0,0 +1,72 @@ + +Test AudioContext state updates with suspend() shortly after + construction + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/suspend-with-navigation.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/suspend-with-navigation.html new file mode 100644 index 000000000..b9328ae95 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audiocontext-interface/suspend-with-navigation.html @@ -0,0 +1,65 @@ + + +AudioContext.suspend() with navigation + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/.gitkeep b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/audionode-channel-rules.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/audionode-channel-rules.html new file mode 100644 index 000000000..9067e6869 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/audionode-channel-rules.html @@ -0,0 +1,278 @@ + + + + + audionode-channel-rules.html + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/audionode-connect-method-chaining.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/audionode-connect-method-chaining.html new file mode 100644 index 000000000..dcda26d7f --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/audionode-connect-method-chaining.html @@ -0,0 +1,150 @@ + + + + AudioNode.connect() Method Chaining and Validation Tests + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/audionode-connect-order.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/audionode-connect-order.html new file mode 100644 index 000000000..b663216a0 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/audionode-connect-order.html @@ -0,0 +1,64 @@ + + + + + AudioNode: Connection Order Robustness + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/audionode-connect-return-value.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/audionode-connect-return-value.html new file mode 100644 index 000000000..3af44fb7a --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/audionode-connect-return-value.html @@ -0,0 +1,15 @@ + +Test the return value of connect when connecting two AudioNodes + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/audionode-disconnect-audioparam.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/audionode-disconnect-audioparam.html new file mode 100644 index 000000000..0b09edd4a --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/audionode-disconnect-audioparam.html @@ -0,0 +1,221 @@ + + + + + audionode-disconnect-audioparam.html + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/audionode-disconnect.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/audionode-disconnect.html new file mode 100644 index 000000000..65b93222d --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/audionode-disconnect.html @@ -0,0 +1,298 @@ + + + + + audionode-disconnect.html + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/audionode-iframe.window.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/audionode-iframe.window.js new file mode 100644 index 000000000..89bdf2aa9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/audionode-iframe.window.js @@ -0,0 +1,14 @@ +test(function() { + const iframe = + document.createElementNS('http://www.w3.org/1999/xhtml', 'iframe'); + document.body.appendChild(iframe); + + // Create AudioContext and AudioNode from iframe + const context = new iframe.contentWindow.AudioContext(); + const source = context.createOscillator(); + source.connect(context.destination); + + // AudioContext should be put closed state after iframe destroyed + document.body.removeChild(iframe); + assert_equals(context.state, 'closed'); +}, 'Call a constructor from iframe page and then destroy the iframe'); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/audionode.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/audionode.html new file mode 100644 index 000000000..9599c56ba --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/audionode.html @@ -0,0 +1,72 @@ + + + + + AudioNode: Basic Interface Tests + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/channel-mode-interp-basic.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/channel-mode-interp-basic.html new file mode 100644 index 000000000..35cfca8e4 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/channel-mode-interp-basic.html @@ -0,0 +1,66 @@ + + + + + Test Setting of channelCountMode and channelInterpretation + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/different-contexts.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/different-contexts.html new file mode 100644 index 000000000..63000250a --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audionode-interface/different-contexts.html @@ -0,0 +1,47 @@ + + + + + Connections and disconnections with different contexts + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/.gitkeep b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/adding-events.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/adding-events.html new file mode 100644 index 000000000..ad4cfc9ce --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/adding-events.html @@ -0,0 +1,146 @@ + + + + Adding Events + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-cancel-and-hold.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-cancel-and-hold.html new file mode 100644 index 000000000..0a8e7a7f2 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-cancel-and-hold.html @@ -0,0 +1,855 @@ + + + + + Test CancelValuesAndHoldAtTime + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-close.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-close.html new file mode 100644 index 000000000..4586ffebf --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-close.html @@ -0,0 +1,159 @@ + + + + Test AudioParam events very close in time + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-connect-audioratesignal.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-connect-audioratesignal.html new file mode 100644 index 000000000..61990739a --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-connect-audioratesignal.html @@ -0,0 +1,98 @@ + + + + + + audioparam-connect-audioratesignal.html + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-default-value.window.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-default-value.window.js new file mode 100644 index 000000000..ea7d73172 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-default-value.window.js @@ -0,0 +1,25 @@ +'use strict'; + +test(() => { + const context = new OfflineAudioContext(1, 1, 44100); + const gainNode = new GainNode(context); + assert_equals(gainNode.gain.defaultValue, 1, + 'GainNode.gain.defaultValue should be 1.'); +}, 'AudioParam: defaultValue attribute value'); + +test(() => { + const context = new OfflineAudioContext(1, 1, 44100); + const gainNode = new GainNode(context); + assert_readonly(gainNode.gain, 'defaultValue'); +}, 'AudioParam: defaultValue is a read-only attribute'); + +test(() => { + const context = new OfflineAudioContext(1, 1, 44100); + const initialValue = -1; + const gainNode = new GainNode(context, { + gain: initialValue, + }); + assert_equals(gainNode.gain.value, initialValue, + 'GainNode.gain.value should be initialized to the value ' + + 'from the constructor.'); +}, 'AudioParam: value attribute is initialized correctly'); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values.html new file mode 100644 index 000000000..982731d33 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values.html @@ -0,0 +1,240 @@ + + + + + audioparam-exceptional-values.html + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-exponentialRampToValueAtTime.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-exponentialRampToValueAtTime.html new file mode 100644 index 000000000..bec4c1286 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-exponentialRampToValueAtTime.html @@ -0,0 +1,63 @@ + + + + + Test AudioParam.exponentialRampToValueAtTime + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-large-endtime.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-large-endtime.html new file mode 100644 index 000000000..d8f38eeba --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-large-endtime.html @@ -0,0 +1,73 @@ + + + + + AudioParam with Huge End Time + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-linearRampToValueAtTime.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-linearRampToValueAtTime.html new file mode 100644 index 000000000..509c254d9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-linearRampToValueAtTime.html @@ -0,0 +1,60 @@ + + + + + Test AudioParam.linearRampToValueAtTime + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-method-chaining.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-method-chaining.html new file mode 100644 index 000000000..51709681b --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-method-chaining.html @@ -0,0 +1,140 @@ + + + + AudioParam Method Chaining + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-nominal-range.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-nominal-range.html new file mode 100644 index 000000000..517fc6e95 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-nominal-range.html @@ -0,0 +1,497 @@ + + + + + Test AudioParam Nominal Range Values + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setTargetAtTime.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setTargetAtTime.html new file mode 100644 index 000000000..faf00c007 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setTargetAtTime.html @@ -0,0 +1,61 @@ + + + + + Test AudioParam.setTargetAtTime + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueAtTime.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueAtTime.html new file mode 100644 index 000000000..ab2edfd00 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueAtTime.html @@ -0,0 +1,57 @@ + + + + + audioparam-setValueAtTime.html + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html new file mode 100644 index 000000000..ed0c15fb9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html @@ -0,0 +1,426 @@ + + + + + Test Exceptions from setValueCurveAtTime + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurveAtTime.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurveAtTime.html new file mode 100644 index 000000000..9f34f5e15 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurveAtTime.html @@ -0,0 +1,88 @@ + + + + AudioParam.setValueCurveAtTime + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-summingjunction.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-summingjunction.html new file mode 100644 index 000000000..5bdc1a148 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-summingjunction.html @@ -0,0 +1,110 @@ + + + + + audioparam-summingjunction.html + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/automation-rate-testing.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/automation-rate-testing.js new file mode 100644 index 000000000..241dffabc --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/automation-rate-testing.js @@ -0,0 +1,328 @@ +// Test k-rate vs a-rate AudioParams. +// +// |options| describes how the testing of the AudioParam should be done: +// +// sourceNodeName: name of source node to use for testing; defaults to +// 'OscillatorNode'. If set to 'none', then no source node +// is created for testing and it is assumed that the AudioNode +// under test are sources and need to be started. +// verifyPieceWiseConstant: if true, verify that the k-rate output is +// piecewise constant for each render quantum. +// nodeName: name of the AudioNode to be tested +// nodeOptions: options to be used in the AudioNode constructor +// +// prefix: Prefix for all output messages (to make them unique for +// testharness) +// +// rateSettings: A vector of dictionaries specifying how to set the automation +// rate(s): +// name: Name of the AudioParam +// value: The automation rate for the AudioParam given by |name|. +// +// automations: A vector of dictionaries specifying how to automate each +// AudioParam: +// name: Name of the AudioParam +// +// methods: A vector of dictionaries specifying the automation methods to +// be used for testing: +// name: Automation method to call +// options: Arguments for the automation method +// +// Testing is somewhat rudimentary. We create two nodes of the same type. One +// node uses the default automation rates for each AudioParam (expecting them to +// be a-rate). The second node sets the automation rate of AudioParams to +// "k-rate". The set is speciified by |options.rateSettings|. +// +// For both of these nodes, the same set of automation methods (given by +// |options.automations|) is applied. A simple oscillator is connected to each +// node which in turn are connected to different channels of an offline context. +// Channel 0 is the k-rate node output; channel 1, the a-rate output; and +// channel 2, the difference between the outputs. +// +// Success is declared if the difference signal is not exactly zero. This means +// the automations did different things, as expected. +// +// The promise from |startRendering| is returned. +function doTest(context, should, options) { + let merger = new ChannelMergerNode( + context, {numberOfInputs: context.destination.channelCount}); + merger.connect(context.destination); + + let src = null; + + // Skip creating a source to drive the graph if |sourceNodeName| is 'none'. + // If |sourceNodeName| is given, use that, else default to OscillatorNode. + if (options.sourceNodeName !== 'none') { + src = new window[options.sourceNodeName || 'OscillatorNode'](context); + } + + let kRateNode = new window[options.nodeName](context, options.nodeOptions); + let aRateNode = new window[options.nodeName](context, options.nodeOptions); + let inverter = new GainNode(context, {gain: -1}); + + // Set kRateNode filter to use k-rate params. + options.rateSettings.forEach(setting => { + kRateNode[setting.name].automationRate = setting.value; + // Mostly for documentation in the output. These should always + // pass. + should( + kRateNode[setting.name].automationRate, + `${options.prefix}: Setting ${ + setting.name + }.automationRate to "${setting.value}"`) + .beEqualTo(setting.value); + }); + + // Run through all automations for each node separately. (Mostly to keep + // output of automations together.) + options.automations.forEach(param => { + param.methods.forEach(method => { + // Most for documentation in the output. These should never throw. + let message = `${param.name}.${method.name}(${method.options})` + should(() => { + kRateNode[param.name][method.name](...method.options); + }, options.prefix + ': k-rate node: ' + message).notThrow(); + }); + }); + options.automations.forEach(param => { + param.methods.forEach(method => { + // Most for documentation in the output. These should never throw. + let message = `${param.name}.${method.name}(${method.options})` + should(() => { + aRateNode[param.name][method.name](...method.options); + }, options.prefix + ': a-rate node:' + message).notThrow(); + }); + }); + + // Connect the source, if specified. + if (src) { + src.connect(kRateNode); + src.connect(aRateNode); + } + + // The k-rate result is channel 0, and the a-rate result is channel 1. + kRateNode.connect(merger, 0, 0); + aRateNode.connect(merger, 0, 1); + + // Compute the difference between the a-rate and k-rate results and send + // that to channel 2. + kRateNode.connect(merger, 0, 2); + aRateNode.connect(inverter).connect(merger, 0, 2); + + if (src) { + src.start(); + } else { + // If there's no source, then assume the test nodes are sources and start + // them. + kRateNode.start(); + aRateNode.start(); + } + + return context.startRendering().then(renderedBuffer => { + let kRateOutput = renderedBuffer.getChannelData(0); + let aRateOutput = renderedBuffer.getChannelData(1); + let diff = renderedBuffer.getChannelData(2); + + // Some informative messages to print out values of the k-rate and + // a-rate outputs. These should always pass. + should( + kRateOutput, `${options.prefix}: Output of k-rate ${options.nodeName}`) + .beEqualToArray(kRateOutput); + should( + aRateOutput, `${options.prefix}: Output of a-rate ${options.nodeName}`) + .beEqualToArray(aRateOutput); + + // The real test. If k-rate AudioParam is working correctly, the + // k-rate result MUST differ from the a-rate result. + should( + diff, + `${ + options.prefix + }: Difference between a-rate and k-rate ${options.nodeName}`) + .notBeConstantValueOf(0); + + if (options.verifyPieceWiseConstant) { + // Verify that the output from the k-rate parameter is step-wise + // constant. + for (let k = 0; k < kRateOutput.length; k += 128) { + should( + kRateOutput.slice(k, k + 128), + `${options.prefix} k-rate output [${k}: ${k + 127}]`) + .beConstantValueOf(kRateOutput[k]); + } + } + }); +} + +// Test k-rate vs a-rate AudioParams. +// +// |options| describes how the testing of the AudioParam should be done: +// +// sourceNodeName: name of source node to use for testing; defaults to +// 'OscillatorNode'. If set to 'none', then no source node +// is created for testing and it is assumed that the AudioNode +// under test are sources and need to be started. +// verifyPieceWiseConstant: if true, verify that the k-rate output is +// piecewise constant for each render quantum. +// nodeName: name of the AudioNode to be tested +// nodeOptions: options to be used in the AudioNode constructor +// +// prefix: Prefix for all output messages (to make them unique for +// testharness) +// +// rateSettings: A vector of dictionaries specifying how to set the automation +// rate(s): +// name: Name of the AudioParam +// value: The automation rate for the AudioParam given by |name|. +// +// automations: A vector of dictionaries specifying how to automate each +// AudioParam: +// name: Name of the AudioParam +// +// methods: A vector of dictionaries specifying the automation methods to +// be used for testing: +// name: Automation method to call +// options: Arguments for the automation method +// +// Testing is somewhat rudimentary. We create two nodes of the same type. One +// node uses the default automation rates for each AudioParam (expecting them to +// be a-rate). The second node sets the automation rate of AudioParams to +// "k-rate". The set is speciified by |options.rateSettings|. +// +// For both of these nodes, the same set of automation methods (given by +// |options.automations|) is applied. A simple oscillator is connected to each +// node which in turn are connected to different channels of an offline context. +// Channel 0 is the k-rate node output; channel 1, the a-rate output; and +// channel 2, the difference between the outputs. +// +// Success is declared if the difference signal is not exactly zero. This means +// the automations did different things, as expected. +// +// The promise from |startRendering| is returned. +function doTest_W3TH(context, options) { + const merger = new ChannelMergerNode(context, { + numberOfInputs: context.destination.channelCount + }); + merger.connect(context.destination); + + let src = null; + + // Skip creating a source to drive the graph if |sourceNodeName| is 'none'. + // If |sourceNodeName| is given, use that, else default to OscillatorNode. + if (options.sourceNodeName !== 'none') { + src = new window[options.sourceNodeName || 'OscillatorNode'](context); + } + + const kRateNode = new window[options.nodeName](context, options.nodeOptions); + const aRateNode = new window[options.nodeName](context, options.nodeOptions); + const inverter = new GainNode(context, { gain: -1 }); + + // Set kRateNode filter to use k-rate params. + options.rateSettings.forEach(setting => { + kRateNode[setting.name].automationRate = setting.value; + // Mostly for documentation in the output. These should always + // pass. + assert_equals( + kRateNode[setting.name].automationRate, setting.value, + `${options.prefix}: Setting ${setting.name}.automationRate ` + + `to "${setting.value}"`); + }); + + // Run through all automations for each node separately. (Mostly to keep + // output of automations together.) + options.automations.forEach(param => { + param.methods.forEach(method => { + // Mostly for documentation in the output. These should never throw. + const message = `${param.name}.${method.name}(${method.options})`; + try { + kRateNode[param.name][method.name](...method.options); + } catch (e) { + assert_unreached( + `${options.prefix}: k-rate node: ${message} threw: ${e.message}`); + } + }); + }); + options.automations.forEach(param => { + param.methods.forEach(method => { + // Mostly for documentation in the output. These should never throw. + const message = `${param.name}.${method.name}(${method.options})`; + try { + aRateNode[param.name][method.name](...method.options); + } catch (e) { + assert_unreached( + `${options.prefix}: a-rate node: ${message} threw: ${e.message}`); + } + }); + }); + + // Connect the source, if specified. + if (src) { + src.connect(kRateNode); + src.connect(aRateNode); + } + + // The k-rate result is channel 0, and the a-rate result is channel 1. + kRateNode.connect(merger, 0, 0); + aRateNode.connect(merger, 0, 1); + + // Compute the difference between the a-rate and k-rate results and send + // that to channel 2. + kRateNode.connect(merger, 0, 2); + aRateNode.connect(inverter).connect(merger, 0, 2); + + if (src) { + src.start(); + } else { + // If there's no source, then assume the test nodes are sources and start + // them. + kRateNode.start(); + aRateNode.start(); + } + + return context.startRendering().then(renderedBuffer => { + const kRateOutput = renderedBuffer.getChannelData(0); + const aRateOutput = renderedBuffer.getChannelData(1); + const diff = renderedBuffer.getChannelData(2); + + // Some informative messages to print out values of the k-rate and + // a-rate outputs. These should always pass. + // (In testharness, assertions only report on failure, + // so we sanity-check types.) + assert_true( + kRateOutput instanceof Float32Array, + `${options.prefix}: Output of k-rate `+ + `${options.nodeName} is Float32Array`); + assert_true( + aRateOutput instanceof Float32Array, + `${options.prefix}: Output of a-rate `+ + `${options.nodeName} is Float32Array`); + + // The real test. If k-rate AudioParam is working correctly, the + // k-rate result MUST differ from the a-rate result. + let allZero = true; + for (let i = 0; i < diff.length; ++i) { + if (diff[i] !== 0) {allZero = false; break;} + } + assert_false( + allZero, + `${options.prefix}: Difference between a-rate and k-rate` + + `${options.nodeName} must not be identically 0`); + + if (options.verifyPieceWiseConstant) { + // Verify that the output from the k-rate parameter is step-wise + // constant. + for (let k = 0; k < kRateOutput.length; k += 128) { + const end = Math.min(k + 128, kRateOutput.length); + const v0 = kRateOutput[k]; + for (let i = k + 1; i < end; ++i) { + assert_equals( + kRateOutput[i], + v0, + `${options.prefix} k-rate output [${k}: ${end - 1}]` + + `should be piecewise constant`, + ); + } + } + } + }); +} diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/automation-rate.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/automation-rate.html new file mode 100644 index 000000000..c6874d81b --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/automation-rate.html @@ -0,0 +1,157 @@ + + + + AudioParam.automationRate tests + + + + + + + + \ No newline at end of file diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/cancel-scheduled-values.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/cancel-scheduled-values.html new file mode 100644 index 000000000..d1bcda7f4 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/cancel-scheduled-values.html @@ -0,0 +1,116 @@ + + + + + cancelScheduledValues + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/event-insertion.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/event-insertion.html new file mode 100644 index 000000000..b846f982a --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/event-insertion.html @@ -0,0 +1,411 @@ + + + + + Test Handling of Event Insertion + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/exponentialRamp-special-cases.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/exponentialRamp-special-cases.html new file mode 100644 index 000000000..d19780982 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/exponentialRamp-special-cases.html @@ -0,0 +1,58 @@ + +Test exponentialRampToValueAtTime() special cases + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-audiobuffersource-connections.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-audiobuffersource-connections.html new file mode 100644 index 000000000..5fa43d7e9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-audiobuffersource-connections.html @@ -0,0 +1,146 @@ + + + + k-rate AudioParams with inputs for AudioBufferSourceNode + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-audioworklet-connections.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-audioworklet-connections.https.html new file mode 100644 index 000000000..8052f1320 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-audioworklet-connections.https.html @@ -0,0 +1,68 @@ + + + + + Test k-rate AudioParams with inputs for AudioWorkletNode + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-audioworklet.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-audioworklet.https.html new file mode 100644 index 000000000..9e239d3a3 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-audioworklet.https.html @@ -0,0 +1,61 @@ + + + + Test k-rate AudioParam of AudioWorkletNode + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-biquad-connection.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-biquad-connection.html new file mode 100644 index 000000000..ab9df8740 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-biquad-connection.html @@ -0,0 +1,456 @@ + + + + Test k-rate AudioParam Inputs for BiquadFilterNode + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-biquad.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-biquad.html new file mode 100644 index 000000000..14f8ea5b6 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-biquad.html @@ -0,0 +1,103 @@ + + + + Test k-rate AudioParams of BiquadFilterNode + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-connections.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-connections.html new file mode 100644 index 000000000..6a46da41d --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-connections.html @@ -0,0 +1,130 @@ + + + + k-rate AudioParams with Inputs + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-constant-source.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-constant-source.html new file mode 100644 index 000000000..0bea5c91f --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-constant-source.html @@ -0,0 +1,176 @@ + + + + Test k-rate AudioParam of ConstantSourceNode + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-delay-connections.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-delay-connections.html new file mode 100644 index 000000000..81f42f355 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-delay-connections.html @@ -0,0 +1,111 @@ + + + + DelayNode delayTime with k-rate input should match automation + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-delay.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-delay.html new file mode 100644 index 000000000..5465c3943 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-delay.html @@ -0,0 +1,49 @@ + + + + Test k-rate AudioParam of DelayNode + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-dynamics-compressor-connections.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-dynamics-compressor-connections.html new file mode 100644 index 000000000..15db310e1 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-dynamics-compressor-connections.html @@ -0,0 +1,104 @@ + + + + k-rate AudioParams with inputs for DynamicsCompressorNode + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-gain.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-gain.html new file mode 100644 index 000000000..887d9f78d --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-gain.html @@ -0,0 +1,47 @@ + + + + Test k-rate AudioParam of GainNode + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-oscillator-connections.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-oscillator-connections.html new file mode 100644 index 000000000..475b36436 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-oscillator-connections.html @@ -0,0 +1,578 @@ + + + + + k-rate AudioParams with inputs for OscillatorNode + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-oscillator.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-oscillator.html new file mode 100644 index 000000000..83a701105 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-oscillator.html @@ -0,0 +1,72 @@ + + + + Test k-rate AudioParams of OscillatorNode + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-panner-connections.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-panner-connections.html new file mode 100644 index 000000000..001cf63bd --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-panner-connections.html @@ -0,0 +1,238 @@ + + + + + k-rate AudioParams with inputs for PannerNode + + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-panner.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-panner.html new file mode 100644 index 000000000..69594517d --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-panner.html @@ -0,0 +1,228 @@ + + + + Test k-rate AudioParams of PannerNode + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-stereo-panner.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-stereo-panner.html new file mode 100644 index 000000000..06905b89c --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-stereo-panner.html @@ -0,0 +1,48 @@ + + + + Test k-rate AudioParam of StereoPannerNode + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/moderate-exponentialRamp.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/moderate-exponentialRamp.html new file mode 100644 index 000000000..cf32d253a --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/moderate-exponentialRamp.html @@ -0,0 +1,50 @@ + +Test exponentialRampToValueAtTime() with a moderate ratio of change + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/nan-param.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/nan-param.html new file mode 100644 index 000000000..1993d23de --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/nan-param.html @@ -0,0 +1,87 @@ + + + + Test Flushing of NaN to Zero in AudioParams + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/retrospective-exponentialRampToValueAtTime.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/retrospective-exponentialRampToValueAtTime.html new file mode 100644 index 000000000..c81c3ad23 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/retrospective-exponentialRampToValueAtTime.html @@ -0,0 +1,70 @@ + + + + + Test exponentialRampToValue with end time in the past + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/retrospective-linearRampToValueAtTime.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/retrospective-linearRampToValueAtTime.html new file mode 100644 index 000000000..9f5e55fe5 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/retrospective-linearRampToValueAtTime.html @@ -0,0 +1,70 @@ + + + + + Test linearRampToValue with end time in the past + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/retrospective-setTargetAtTime.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/retrospective-setTargetAtTime.html new file mode 100644 index 000000000..18beca5d2 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/retrospective-setTargetAtTime.html @@ -0,0 +1,63 @@ + + + + + Test setTargetAtTime with start time in the past + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/retrospective-setValueAtTime.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/retrospective-setValueAtTime.html new file mode 100644 index 000000000..8f271cee0 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/retrospective-setValueAtTime.html @@ -0,0 +1,60 @@ + + + + Test setValueAtTime with startTime in the past + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/retrospective-setValueCurveAtTime.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/retrospective-setValueCurveAtTime.html new file mode 100644 index 000000000..451b6ea82 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/retrospective-setValueCurveAtTime.html @@ -0,0 +1,67 @@ + + + + Test SetValueCurve with start time in the past + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/retrospective-test.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/retrospective-test.js new file mode 100644 index 000000000..bbda190f0 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/retrospective-test.js @@ -0,0 +1,29 @@ +// Create an audio graph on an offline context that consists of a +// constant source and two gain nodes. One of the nodes is the node te +// be tested and the other is the reference node. The output from the +// test node is in channel 0 of the offline context; the reference +// node is in channel 1. +// +// Returns a dictionary with the context, source node, the test node, +// and the reference node. +function setupRetrospectiveGraph() { + // Use a sample rate that is a power of two to eliminate round-off + // in computing the currentTime. + let context = new OfflineAudioContext(2, 16384, 16384); + let source = new ConstantSourceNode(context); + + let test = new GainNode(context); + let reference = new GainNode(context); + + source.connect(test); + source.connect(reference); + + let merger = new ChannelMergerNode( + context, {numberOfInputs: context.destination.channelCount}); + test.connect(merger, 0, 0); + reference.connect(merger, 0, 1); + + merger.connect(context.destination); + + return {context: context, source: source, test: test, reference: reference}; +} diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/set-target-conv.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/set-target-conv.html new file mode 100644 index 000000000..56950819c --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/set-target-conv.html @@ -0,0 +1,78 @@ + + + + Test convergence of setTargetAtTime + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/setTargetAtTime-after-event-within-block.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/setTargetAtTime-after-event-within-block.html new file mode 100644 index 000000000..ca02b0db9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/setTargetAtTime-after-event-within-block.html @@ -0,0 +1,99 @@ + +Test setTargetAtTime after an event in the same processing block + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/setValueAtTime-within-block.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/setValueAtTime-within-block.html new file mode 100644 index 000000000..36fde2b99 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioparam-interface/setValueAtTime-within-block.html @@ -0,0 +1,48 @@ + +Test setValueAtTime with start time not on a block boundary + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..1d37287c0 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: audio-worklet + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-addmodule-resolution.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-addmodule-resolution.https.html new file mode 100644 index 000000000..b42d81a82 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-addmodule-resolution.https.html @@ -0,0 +1,46 @@ + + + + + Test the invocation order of AudioWorklet.addModule() and BaseAudioContext + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-audioparam-iterable.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-audioparam-iterable.https.html new file mode 100644 index 000000000..9e93f48ab --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-audioparam-iterable.https.html @@ -0,0 +1,205 @@ + + + + + + Test get parameterDescriptor as various iterables + + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-audioparam-range.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-audioparam-range.https.html new file mode 100644 index 000000000..064c8c866 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-audioparam-range.https.html @@ -0,0 +1,91 @@ + + + + + Test AudioWorkletProcessor parameterDescriptors values range + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-audioparam-size.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-audioparam-size.https.html new file mode 100644 index 000000000..9578b2688 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-audioparam-size.https.html @@ -0,0 +1,96 @@ + + + + + Test AudioParam Array Size + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-audioparam.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-audioparam.https.html new file mode 100644 index 000000000..2644dc870 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-audioparam.https.html @@ -0,0 +1,65 @@ + + + + + Test AudioWorkletNode's basic AudioParam features + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-denormals.https.window.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-denormals.https.window.js new file mode 100644 index 000000000..39b9be56e --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-denormals.https.window.js @@ -0,0 +1,26 @@ +'use strict'; + +// Test if the JS code execution in AudioWorkletGlobalScope can handle the +// denormals properly. For more details, see: +// https://esdiscuss.org/topic/float-denormal-issue-in-javascript-processor-node-in-web-audio-api +promise_test(async () => { + // In the main thread, the denormals should be non-zeros. + assert_not_equals(Number.MIN_VALUE, 0.0, + 'The denormals should be non-zeros.'); + + const context = new AudioContext(); + await context.audioWorklet.addModule( + './processors/denormal-test-processor.js'); + + const denormalTestProcessor = new AudioWorkletNode(context, 'denormal-test'); + + return new Promise(resolve => { + denormalTestProcessor.port.onmessage = resolve; + denormalTestProcessor.connect(context.destination); + }).then(event => { + // In the AudioWorkletGlobalScope, the denormals should be non-zeros too. + assert_true( + event.data.result, + 'The denormals should be non-zeros in AudioWorkletGlobalScope.'); + }); +}, 'Test denormal behavior in AudioWorkletGlobalScope'); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-messageport.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-messageport.https.html new file mode 100644 index 000000000..335c6796e --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-messageport.https.html @@ -0,0 +1,80 @@ + + + + + Test MessagePort in AudioWorkletNode and AudioWorkletProcessor + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-postmessage-sharedarraybuffer.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-postmessage-sharedarraybuffer.https.html new file mode 100644 index 000000000..a5dd00498 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-postmessage-sharedarraybuffer.https.html @@ -0,0 +1,76 @@ + + + + + Test passing SharedArrayBuffer to an AudioWorklet + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-postmessage-sharedarraybuffer.https.html.headers b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-postmessage-sharedarraybuffer.https.html.headers new file mode 100644 index 000000000..63b60e490 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-postmessage-sharedarraybuffer.https.html.headers @@ -0,0 +1,2 @@ +Cross-Origin-Opener-Policy: same-origin +Cross-Origin-Embedder-Policy: require-corp diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-registerprocessor-called-on-globalthis.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-registerprocessor-called-on-globalthis.https.html new file mode 100644 index 000000000..718cadffc --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-registerprocessor-called-on-globalthis.https.html @@ -0,0 +1,29 @@ + + + + + Test AudioWorkletGlobalScope's registerProcessor() called on globalThis + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-registerprocessor-constructor.https.window.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-registerprocessor-constructor.https.window.js new file mode 100644 index 000000000..679480b48 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-registerprocessor-constructor.https.window.js @@ -0,0 +1,33 @@ +'use strict'; + +// https://crbug.com/1078902: this test verifies two TypeError cases from +// registerProcessor() method: +// - When a given parameter is not a Function. +// - When a given parameter is not a constructor. +const TestDescriptions = [ + 'The parameter should be of type "Function".', + 'The class definition of AudioWorkletProcessor should be a constructor.' +]; + +// See `register-processor-exception.js` file for the test details. +promise_test(async () => { + const context = new AudioContext(); + await context.audioWorklet.addModule( + './processors/register-processor-typeerrors.js'); + const messenger = new AudioWorkletNode(context, 'messenger-processor'); + + return new Promise(resolve => { + let testIndex = 0; + messenger.port.onmessage = (event) => { + const exception = event.data; + assert_equals(exception.name, 'TypeError', + TestDescriptions[testIndex]); + if (++testIndex === TestDescriptions.length) { + resolve(); + } + }; + + // Start the test on AudioWorkletGlobalScope. + messenger.port.postMessage({}); + }); +}, 'Verifies two TypeError cases from registerProcessor() method.'); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-registerprocessor-dynamic.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-registerprocessor-dynamic.https.html new file mode 100644 index 000000000..de31f7142 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-registerprocessor-dynamic.https.html @@ -0,0 +1,36 @@ + + + + + Test dynamic registerProcessor() calls in AudioWorkletGlobalScope + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-rendersizehint.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-rendersizehint.https.html new file mode 100644 index 000000000..1be72f1e0 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-rendersizehint.https.html @@ -0,0 +1,70 @@ + + + + + Test AudioContextOptions renderSizeHint with AudioWorklet + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-suspend.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-suspend.https.html new file mode 100644 index 000000000..685546aeb --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-suspend.https.html @@ -0,0 +1,39 @@ + + + + + Test if activation of worklet thread does not resume context rendering. + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-throw-onmessage.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-throw-onmessage.https.html new file mode 100644 index 000000000..3a480464e --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-throw-onmessage.https.html @@ -0,0 +1,62 @@ + + + + + + Test the behaviour of AudioWorkletProcessor when an `onmessage` handler + throws. + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletglobalscope-creation-time.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletglobalscope-creation-time.https.html new file mode 100644 index 000000000..6fd343f97 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletglobalscope-creation-time.https.html @@ -0,0 +1,51 @@ + +Test consistency of processing after resume() + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletglobalscope-sample-rate.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletglobalscope-sample-rate.https.html new file mode 100644 index 000000000..84458d0aa --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletglobalscope-sample-rate.https.html @@ -0,0 +1,44 @@ + + + + + Test sampleRate in AudioWorkletGlobalScope + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletglobalscope-timing-info.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletglobalscope-timing-info.https.html new file mode 100644 index 000000000..75ffe9b17 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletglobalscope-timing-info.https.html @@ -0,0 +1,50 @@ + + + + + Test currentTime and currentFrame in AudioWorkletGlobalScope + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-automatic-pull.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-automatic-pull.https.html new file mode 100644 index 000000000..330b359f7 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-automatic-pull.https.html @@ -0,0 +1,73 @@ + + + + + Test AudioWorkletNode's automatic pull feature + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-channel-count.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-channel-count.https.html new file mode 100644 index 000000000..8ec69422a --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-channel-count.https.html @@ -0,0 +1,79 @@ + + + + + Test AudioWorkletNode's dynamic channel count feature + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-construction.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-construction.https.html new file mode 100644 index 000000000..8b7704a78 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-construction.https.html @@ -0,0 +1,53 @@ + + + + + Test the construction of AudioWorkletNode with real-time context + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-constructor-options.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-constructor-options.https.html new file mode 100644 index 000000000..846421cb9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-constructor-options.https.html @@ -0,0 +1,110 @@ + + + + AudioWorkletNodeOptions: Basic Construction & Validation + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-disconnected-input.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-disconnected-input.https.html new file mode 100644 index 000000000..481f80c32 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-disconnected-input.https.html @@ -0,0 +1,89 @@ + + + + + Test AudioWorkletNode's Disconnected Input Array Length + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-onerror.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-onerror.https.html new file mode 100644 index 000000000..584adadbd --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-onerror.https.html @@ -0,0 +1,63 @@ + +Test onprocessorerror handler in AudioWorkletNode + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-output-channel-count.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-output-channel-count.https.html new file mode 100644 index 000000000..ce103e737 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-output-channel-count.https.html @@ -0,0 +1,73 @@ + + + + + Test the construction of AudioWorkletNode with real-time context + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-no-process-function.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-no-process-function.https.html new file mode 100644 index 000000000..e5578c6f9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-no-process-function.https.html @@ -0,0 +1,44 @@ + +Test consistency of processing after resume() + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-no-process.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-no-process.js new file mode 100644 index 000000000..0b856a20b --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-no-process.js @@ -0,0 +1,19 @@ +'use strict'; + +/** + * @class NoProcessDef + * @extends AudioWorkletProcessor + * + * This processor class demonstrates an AudioWorkletProcessor with no + * process named function defined. + */ +class NoProcessDef extends AudioWorkletProcessor { + constructor() { + super(); + this.port.postMessage({ + state: 'created', + }); + } +} + +registerProcessor('audioworkletprocessor-no-process', NoProcessDef); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-options.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-options.https.html new file mode 100644 index 000000000..f7949c645 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-options.https.html @@ -0,0 +1,78 @@ + + + + + Test cross-thread passing of AudioWorkletNodeOptions + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-param-getter-overridden.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-param-getter-overridden.https.html new file mode 100644 index 000000000..7441670ee --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-param-getter-overridden.https.html @@ -0,0 +1,55 @@ + + + + + Test if AudioWorkletProcessor with invalid parameters array getter + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-process-frozen-array.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-process-frozen-array.https.html new file mode 100644 index 000000000..ce0cfa40b --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-process-frozen-array.https.html @@ -0,0 +1,56 @@ + + + + + Test given arrays within AudioWorkletProcessor.process() method + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-process-zero-outputs.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-process-zero-outputs.https.html new file mode 100644 index 000000000..e1c19f0d7 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-process-zero-outputs.https.html @@ -0,0 +1,36 @@ + + + + + Test if |outputs| argument is all zero in AudioWorkletProcessor.process() + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-promises.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-promises.https.html new file mode 100644 index 000000000..079b57b95 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-promises.https.html @@ -0,0 +1,44 @@ + + + + + Test micro task checkpoints in AudioWorkletGlobalScope + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-unconnected-outputs.https.window.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-unconnected-outputs.https.window.js new file mode 100644 index 000000000..16adddd33 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-unconnected-outputs.https.window.js @@ -0,0 +1,129 @@ +'use strict'; + +// This value is used to set the values in an AudioParam. +const TestValue = 0.5; + +// Prepare 4 outputs; 2 outputs will be unconnected for testing. +const WorkletNodeOptions = { + processorOptions: {testValue: TestValue}, + numberOfInputs: 0, + numberOfOutputs: 4 +}; + +// The code for the AWP definition in AudioWorkletGlobalScope. +const processorCode = () => { + + // This processor sends the `outputs` array to the main thread at the first + // process call - after filling its 2nd output with the test value. + class OutputTestProcessor extends AudioWorkletProcessor { + + constructor(options) { + super(options); + this.testValue = options.processorOptions.testValue; + } + + process(inputs, outputs) { + // Fill the second output of this process with the `testValue`. + const output = outputs[1]; + for (const channel of output) { + channel.fill(this.testValue); + } + + // Send the outputs array and stop rendering. + this.port.postMessage({outputs}); + return false; + } + } + + registerProcessor('output-test-processor', OutputTestProcessor); + + // This process has an AudioParam and sends the `params` array to the main + // thread at the first process call. + class ParamTestProcessor extends AudioWorkletProcessor { + static get parameterDescriptors() { + return [ + {name: 'testParam', defaultValue: 0.0} + ]; + } + + process(inputs, outputs, params) { + // Send the params array and stop rendering. + this.port.postMessage({paramValues: params.testParam}); + return false; + } + } + + registerProcessor('param-test-processor', ParamTestProcessor); +} + +const initializeAudioContext = async () => { + const context = new AudioContext(); + const moduleString = `(${processorCode.toString()})();`; + const blobUrl = window.URL.createObjectURL( + new Blob([moduleString], {type: 'text/javascript'})); + await context.audioWorklet.addModule(blobUrl); + context.suspend(); + return context; +}; + +// Test if unconnected outputs provides a non-zero length array for channels. +promise_test(async () => { + const context = await initializeAudioContext(); + const outputTester = new AudioWorkletNode( + context, 'output-test-processor', WorkletNodeOptions); + const testGain = new GainNode(context); + + // Connect the 2nd output of the tester to another node. Note that + // `testGain` is not connected to the destination. + outputTester.connect(testGain, 1); + + // Connect the 4th output of the tester to the destination node. + outputTester.connect(context.destination, 3); + + return new Promise(resolve => { + outputTester.port.onmessage = resolve; + context.resume(); + }).then(event => { + // The number of outputs should be 4, as specified above. + const outputs = event.data.outputs; + assert_equals(outputs.length, WorkletNodeOptions.numberOfOutputs); + for (const output of outputs) { + // Each output should have 1 channel of audio data per spec. + assert_equals(output.length, 1); + for (const channel of output) { + // Each channel should have a non-zero length array. + assert_true(channel.length > 0); + } + } + context.close(); + }); +}, 'Test if unconnected outputs provides a non-zero length array for channels'); + +// Test if outputs connected to AudioParam provides a non-zero length array for +// channels. +promise_test(async () => { + const context = await initializeAudioContext(); + const outputTester = new AudioWorkletNode( + context, 'output-test-processor', WorkletNodeOptions); + const paramTester = new AudioWorkletNode( + context, 'param-test-processor'); + + // Connect the 2nd output of the tester to another node's AudioParam. + outputTester.connect(paramTester.parameters.get('testParam'), 1); + + outputTester.connect(context.destination); + + return new Promise(resolve => { + paramTester.port.onmessage = resolve; + context.resume(); + }).then(event => { + // The resulting values from AudioParam should be a non-zero length array + // filled with `TestValue` above. + const actualValues = event.data.paramValues; + const expectedValues = (new Array(actualValues.length)).fill(TestValue); + assert_true(actualValues.length > 0); + assert_array_equals(actualValues, expectedValues); + context.close(); + }); +}, 'Test if outputs connected to AudioParam provides a non-zero length array ' + + 'for channels'); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/baseaudiocontext-audioworklet.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/baseaudiocontext-audioworklet.https.html new file mode 100644 index 000000000..4281f5637 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/baseaudiocontext-audioworklet.https.html @@ -0,0 +1,30 @@ + + + + + Checking BaseAudioContext.audioWorklet + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/extended-audioworkletnode-with-parameters.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/extended-audioworkletnode-with-parameters.https.html new file mode 100644 index 000000000..75f4aa402 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/extended-audioworkletnode-with-parameters.https.html @@ -0,0 +1,16 @@ + +Test AudioWorkletNode subclass with parameters + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/process-getter.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/process-getter.https.html new file mode 100644 index 000000000..a4c59123a --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/process-getter.https.html @@ -0,0 +1,23 @@ + +Test use of 'process' getter for AudioWorkletProcessor callback + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/process-parameters.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/process-parameters.https.html new file mode 100644 index 000000000..4c6a10dfa --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/process-parameters.https.html @@ -0,0 +1,87 @@ + +Test parameters of process() AudioWorkletProcessor callback + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processor-construction-port.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processor-construction-port.https.html new file mode 100644 index 000000000..6f1aa5922 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processor-construction-port.https.html @@ -0,0 +1,61 @@ + +Test processor port assignment on processor callback function construction + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/active-processing.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/active-processing.js new file mode 100644 index 000000000..ef497733c --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/active-processing.js @@ -0,0 +1,54 @@ +/** + * @class ActiveProcessingTester + * @extends AudioWorkletProcessor + * + * This processor class sends a message to its AudioWorkletNodew whenever the + * number of channels on the input changes. The message includes the actual + * number of channels, the context time at which this occurred, and whether + * we're done processing or not. + */ +class ActiveProcessingTester extends AudioWorkletProcessor { + constructor(options) { + super(options); + this._lastChannelCount = 0; + + // See if user specified a value for test duration. + if (options.hasOwnProperty('processorOptions') && + options.processorOptions.hasOwnProperty('testDuration')) { + this._testDuration = options.processorOptions.testDuration; + } else { + this._testDuration = 5; + } + + // Time at which we'll signal we're done, based on the requested + // |testDuration| + this._endTime = currentTime + this._testDuration; + } + + process(inputs, outputs) { + const input = inputs[0]; + const output = outputs[0]; + const inputChannelCount = input.length; + const isFinished = currentTime > this._endTime; + + // Send a message if we're done or the count changed. + if (isFinished || (inputChannelCount != this._lastChannelCount)) { + this.port.postMessage({ + channelCount: inputChannelCount, + finished: isFinished, + time: currentTime + }); + this._lastChannelCount = inputChannelCount; + } + + // Just copy the input to the output for no particular reason. + for (let channel = 0; channel < input.length; ++channel) { + output[channel].set(input[channel]); + } + + // When we're finished, this method no longer needs to be called. + return !isFinished; + } +} + +registerProcessor('active-processing-tester', ActiveProcessingTester); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/add-offset.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/add-offset.js new file mode 100644 index 000000000..d05056bd8 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/add-offset.js @@ -0,0 +1,34 @@ +/* + * @class AddOffsetProcessor + * @extends AudioWorkletProcessor + * + * Just adds a fixed value to the input + */ +class AddOffsetProcessor extends AudioWorkletProcessor { + constructor(options) { + super(); + + this._offset = options.processorOptions.offset; + } + + process(inputs, outputs) { + // This processor assumes the node has at least 1 input and 1 output. + let input = inputs[0]; + let output = outputs[0]; + let outputChannel = output[0]; + + if (input.length > 0) { + let inputChannel = input[0]; + for (let k = 0; k < outputChannel.length; ++k) + outputChannel[k] = inputChannel[k] + this._offset; + } else { + // No input connected, so pretend it's silence and just fill the + // output with the offset value. + outputChannel.fill(this._offset); + } + + return true; + } +} + +registerProcessor('add-offset-processor', AddOffsetProcessor); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/array-check-processor.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/array-check-processor.js new file mode 100644 index 000000000..d6eeff3d1 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/array-check-processor.js @@ -0,0 +1,94 @@ +/** + * @class ArrayFrozenProcessor + * @extends AudioWorkletProcessor + */ +class ArrayFrozenProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this._messageSent = false; + } + + process(inputs, outputs, parameters) { + const input = inputs[0]; + const output = outputs[0]; + + if (!this._messageSent) { + this.port.postMessage({ + inputLength: input.length, + isInputFrozen: Object.isFrozen(inputs) && Object.isFrozen(input), + outputLength: output.length, + isOutputFrozen: Object.isFrozen(outputs) && Object.isFrozen(output) + }); + this._messageSent = true; + } + + return false; + } +} + +/** + * @class ArrayTransferProcessor + * @extends AudioWorkletProcessor + */ +class ArrayTransferProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this._messageSent = false; + } + + process(inputs, outputs, parameters) { + const input = inputs[0]; + const output = outputs[0]; + + if (!this._messageSent) { + try { + // Transferring Array objects should NOT work. + this.port.postMessage({ + inputs, input, inputChannel: input[0], + outputs, output, outputChannel: output[0] + }, [inputs, input, inputs[0], outputs, output, output[0]]); + // Hence, the following must NOT be reached. + this.port.postMessage({ + type: 'assertion', + success: false, + message: 'Transferring inputs/outputs, an individual input/output ' + + 'array, or a channel Float32Array MUST fail, but succeeded.' + }); + } catch (error) { + this.port.postMessage({ + type: 'assertion', + success: true, + message: 'Transferring inputs/outputs, an individual input/output ' + + 'array, or a channel Float32Array is not allowed as expected.' + }); + } + + try { + // Transferring ArrayBuffers should work. + this.port.postMessage( + {inputChannel: input[0], outputChannel: output[0]}, + [input[0].buffer, output[0].buffer]); + this.port.postMessage({ + type: 'assertion', + success: true, + message: 'Transferring ArrayBuffers was successful as expected.' + }); + } catch (error) { + // This must NOT be reached. + this.port.postMessage({ + type: 'assertion', + success: false, + message: 'Transferring ArrayBuffers unexpectedly failed.' + }); + } + + this.port.postMessage({done: true}); + this._messageSent = true; + } + + return false; + } +} + +registerProcessor('array-frozen-processor', ArrayFrozenProcessor); +registerProcessor('array-transfer-processor', ArrayTransferProcessor); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/channel-count-processor.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/channel-count-processor.js new file mode 100644 index 000000000..556459f46 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/channel-count-processor.js @@ -0,0 +1,19 @@ +/** + * @class ChannelCountProcessor + * @extends AudioWorkletProcessor + */ +class ChannelCountProcessor extends AudioWorkletProcessor { + constructor(options) { + super(options); + } + + process(inputs, outputs) { + this.port.postMessage({ + inputChannel: inputs[0].length, + outputChannel: outputs[0].length + }); + return false; + } +} + +registerProcessor('channel-count', ChannelCountProcessor); \ No newline at end of file diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/construction-port-new-after-new.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/construction-port-new-after-new.js new file mode 100644 index 000000000..d4c63f777 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/construction-port-new-after-new.js @@ -0,0 +1,16 @@ +class NewAfterNew extends AudioWorkletProcessor { + constructor() { + const processor = new AudioWorkletProcessor() + let message = {threw: false}; + try { + new AudioWorkletProcessor(); + } catch (e) { + message.threw = true; + message.errorName = e.name; + message.isTypeError = e instanceof TypeError; + } + processor.port.postMessage(message); + return processor; + } +} +registerProcessor("new-after-new", NewAfterNew); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/construction-port-new-after-super.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/construction-port-new-after-super.js new file mode 100644 index 000000000..a6d4f0e2e --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/construction-port-new-after-super.js @@ -0,0 +1,15 @@ +class NewAfterSuper extends AudioWorkletProcessor { + constructor() { + super() + let message = {threw: false}; + try { + new AudioWorkletProcessor() + } catch (e) { + message.threw = true; + message.errorName = e.name; + message.isTypeError = e instanceof TypeError; + } + this.port.postMessage(message); + } +} +registerProcessor("new-after-super", NewAfterSuper); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/construction-port-singleton.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/construction-port-singleton.js new file mode 100644 index 000000000..c40b5a717 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/construction-port-singleton.js @@ -0,0 +1,16 @@ +let singleton; +class Singleton extends AudioWorkletProcessor { + constructor() { + if (!singleton) { + singleton = new AudioWorkletProcessor(); + singleton.process = function() { + this.port.postMessage({message: "process called"}); + // This function will be called at most once for each AudioWorkletNode + // if the node has no input connections. + return false; + } + } + return singleton; + } +} +registerProcessor("singleton", Singleton); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/construction-port-super-after-new.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/construction-port-super-after-new.js new file mode 100644 index 000000000..e447830c5 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/construction-port-super-after-new.js @@ -0,0 +1,16 @@ +class SuperAfterNew extends AudioWorkletProcessor { + constructor() { + const processor = new AudioWorkletProcessor() + let message = {threw: false}; + try { + super(); + } catch (e) { + message.threw = true; + message.errorName = e.name; + message.isTypeError = e instanceof TypeError; + } + processor.port.postMessage(message); + return processor; + } +} +registerProcessor("super-after-new", SuperAfterNew); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/denormal-test-processor.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/denormal-test-processor.js new file mode 100644 index 000000000..2b7929437 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/denormal-test-processor.js @@ -0,0 +1,12 @@ +class DenormalTestProcessor extends AudioWorkletProcessor { + process() { + // The denormals should be non-zeros. Otherwise, it's a violation of + // ECMA specification: https://tc39.es/ecma262/#sec-number.min_value + this.port.postMessage({ + result: Number.MIN_VALUE !== 0.0 + }); + return false; + } +} + +registerProcessor('denormal-test', DenormalTestProcessor); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/dummy-processor-globalthis.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/dummy-processor-globalthis.js new file mode 100644 index 000000000..d1b16cc9a --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/dummy-processor-globalthis.js @@ -0,0 +1,12 @@ +class DummyProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } + + process(inputs, outputs, parameters) { + // Doesn't do anything here. + return true; + } +} + +globalThis.registerProcessor('dummy-globalthis', DummyProcessor); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/dummy-processor.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/dummy-processor.js new file mode 100644 index 000000000..11155d508 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/dummy-processor.js @@ -0,0 +1,18 @@ +/** + * @class DummyProcessor + * @extends AudioWorkletProcessor + * + * This processor class demonstrates the bare-bone structure of the processor. + */ +class DummyProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } + + process(inputs, outputs, parameters) { + // Doesn't do anything here. + return true; + } +} + +registerProcessor('dummy', DummyProcessor); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/dynamic-register-processor.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/dynamic-register-processor.js new file mode 100644 index 000000000..5e825aebb --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/dynamic-register-processor.js @@ -0,0 +1,22 @@ +class ProcessorA extends AudioWorkletProcessor { + process() { + return true; + } +} + +// ProcessorB registers ProcessorA upon the construction. +class ProcessorB extends AudioWorkletProcessor { + constructor() { + super(); + this.port.onmessage = () => { + registerProcessor('ProcessorA', ProcessorA); + this.port.postMessage({}); + }; + } + + process() { + return true; + } +} + +registerProcessor('ProcessorB', ProcessorB); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/error-processor.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/error-processor.js new file mode 100644 index 000000000..66ff5e2e2 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/error-processor.js @@ -0,0 +1,40 @@ +/** + * @class ConstructorErrorProcessor + * @extends AudioWorkletProcessor + */ +class ConstructorErrorProcessor extends AudioWorkletProcessor { + constructor() { + throw 'ConstructorErrorProcessor: an error thrown from constructor.'; + } + + process() { + return true; + } +} + + +/** + * @class ProcessErrorProcessor + * @extends AudioWorkletProcessor + */ +class ProcessErrorProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } + + process() { + throw 'ProcessErrorProcessor: an error throw from process method.'; + return true; + } +} + + +/** + * @class EmptyErrorProcessor + * @extends AudioWorkletProcessor + */ +class EmptyErrorProcessor extends AudioWorkletProcessor { process() {} } + +registerProcessor('constructor-error', ConstructorErrorProcessor); +registerProcessor('process-error', ProcessErrorProcessor); +registerProcessor('empty-error', EmptyErrorProcessor); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/gain-processor.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/gain-processor.js new file mode 100644 index 000000000..e9e130e37 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/gain-processor.js @@ -0,0 +1,38 @@ +/** + * @class GainProcessor + * @extends AudioWorkletProcessor + * + * This processor class demonstrates the bare-bone structure of the processor. + */ +class GainProcessor extends AudioWorkletProcessor { + static get parameterDescriptors() { + return [ + {name: 'gain', defaultValue: 0.707} + ]; + } + + constructor() { + super(); + } + + process(inputs, outputs, parameters) { + let input = inputs[0]; + let output = outputs[0]; + let gain = parameters.gain; + for (let channel = 0; channel < input.length; ++channel) { + let inputChannel = input[channel]; + let outputChannel = output[channel]; + if (gain.length === 1) { + for (let i = 0; i < inputChannel.length; ++i) + outputChannel[i] = inputChannel[i] * gain[0]; + } else { + for (let i = 0; i < inputChannel.length; ++i) + outputChannel[i] = inputChannel[i] * gain[i]; + } + } + + return true; + } +} + +registerProcessor('gain', GainProcessor); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/input-count-processor.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/input-count-processor.js new file mode 100644 index 000000000..6d53ba84c --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/input-count-processor.js @@ -0,0 +1,22 @@ +/** + * @class CountProcessor + * @extends AudioWorkletProcessor + * + * This processor class just looks at the number of input channels on the first + * input and fills the first output channel with that value. + */ +class CountProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } + + process(inputs, outputs, parameters) { + let input = inputs[0]; + let output = outputs[0]; + output[0].fill(input.length); + + return true; + } +} + +registerProcessor('counter', CountProcessor); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/input-length-processor.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/input-length-processor.js new file mode 100644 index 000000000..be485f03e --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/input-length-processor.js @@ -0,0 +1,27 @@ +/** + * @class InputLengthProcessor + * @extends AudioWorkletProcessor + * + * This processor class just sets the output to the length of the + * input array for verifying that the input length changes when the + * input is disconnected. + */ +class InputLengthProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } + + process(inputs, outputs, parameters) { + let input = inputs[0]; + let output = outputs[0]; + + // Set output channel to the length of the input channel array. + // If the input is unconnected, set the value to zero. + const fillValue = input.length > 0 ? input[0].length : 0; + output[0].fill(fillValue); + + return true; + } +} + +registerProcessor('input-length-processor', InputLengthProcessor); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/invalid-param-array-processor.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/invalid-param-array-processor.js new file mode 100644 index 000000000..e4a5dc39b --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/invalid-param-array-processor.js @@ -0,0 +1,47 @@ +/** + * @class InvalidParamArrayProcessor + * @extends AudioWorkletProcessor + * + * This processor intentionally returns an array with an invalid size when the + * processor's getter is queried. + */ +let singleton = undefined; +let secondFetch = false; +let useDescriptor = false; +let processCounter = 0; + +class InvalidParamArrayProcessor extends AudioWorkletProcessor { + static get parameterDescriptors() { + if (useDescriptor) + return [{name: 'invalidParam'}]; + useDescriptor = true; + return []; + } + + constructor() { + super(); + if (singleton === undefined) + singleton = this; + return singleton; + } + + process(inputs, outputs, parameters) { + const output = outputs[0]; + for (let channel = 0; channel < output.length; ++channel) + output[channel].fill(1); + return false; + } +} + +// This overridden getter is invoked under the hood before process() gets +// called. After this gets called, process() method above will be invalidated, +// and mark the worklet node non-functional. (i.e. in an error state) +Object.defineProperty(Object.prototype, 'invalidParam', {'get': () => { + if (secondFetch) + return new Float32Array(256); + secondFetch = true; + return new Float32Array(128); +}}); + +registerProcessor('invalid-param-array-1', InvalidParamArrayProcessor); +registerProcessor('invalid-param-array-2', InvalidParamArrayProcessor); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/one-pole-processor.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/one-pole-processor.js new file mode 100644 index 000000000..0bcc43f6f --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/one-pole-processor.js @@ -0,0 +1,49 @@ +/** + * @class OnePoleFilter + * @extends AudioWorkletProcessor + * + * A simple One-pole filter. + */ + +class OnePoleFilter extends AudioWorkletProcessor { + + // This gets evaluated as soon as the global scope is created. + static get parameterDescriptors() { + return [{ + name: 'frequency', + defaultValue: 250, + minValue: 0, + maxValue: 0.5 * sampleRate + }]; + } + + constructor() { + super(); + this.updateCoefficientsWithFrequency_(250); + } + + updateCoefficientsWithFrequency_(frequency) { + this.b1_ = Math.exp(-2 * Math.PI * frequency / sampleRate); + this.a0_ = 1.0 - this.b1_; + this.z1_ = 0; + } + + process(inputs, outputs, parameters) { + let input = inputs[0]; + let output = outputs[0]; + let frequency = parameters.frequency; + for (let channel = 0; channel < output.length; ++channel) { + let inputChannel = input[channel]; + let outputChannel = output[channel]; + for (let i = 0; i < outputChannel.length; ++i) { + this.updateCoefficientsWithFrequency_(frequency[i]); + this.z1_ = inputChannel[i] * this.a0_ + this.z1_ * this.b1_; + outputChannel[i] = this.z1_; + } + } + + return true; + } +} + +registerProcessor('one-pole-filter', OnePoleFilter); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/option-test-processor.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/option-test-processor.js new file mode 100644 index 000000000..27e1da632 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/option-test-processor.js @@ -0,0 +1,19 @@ +/** + * @class OptionTestProcessor + * @extends AudioWorkletProcessor + * + * This processor class demonstrates the option passing feature by echoing the + * received |nodeOptions| back to the node. + */ +class OptionTestProcessor extends AudioWorkletProcessor { + constructor(nodeOptions) { + super(); + this.port.postMessage(nodeOptions); + } + + process() { + return true; + } +} + +registerProcessor('option-test-processor', OptionTestProcessor); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/param-size-processor.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/param-size-processor.js new file mode 100644 index 000000000..d7ce83650 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/param-size-processor.js @@ -0,0 +1,30 @@ +/** + * @class ParamSizeProcessor + * @extends AudioWorkletProcessor + * + * This processor is a source node which basically outputs the size of the + * AudioParam array for each render quantum. + */ + +class ParamSizeProcessor extends AudioWorkletProcessor { + static get parameterDescriptors() { + return [{name: 'param'}]; + } + + constructor() { + super(); + } + + process(inputs, outputs, parameters) { + let output = outputs[0]; + let param = parameters.param; + + for (let channel = 0; channel < output.length; ++channel) { + output[channel].fill(param.length); + } + + return true; + } +} + +registerProcessor('param-size', ParamSizeProcessor); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/port-processor.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/port-processor.js new file mode 100644 index 000000000..c3fa52faf --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/port-processor.js @@ -0,0 +1,36 @@ +/** + * @class PortProcessor + * @extends AudioWorkletProcessor + * + * This processor class demonstrates the message port functionality. + */ +class PortProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this.port.onmessage = this.handleMessage.bind(this); + this.port.postMessage({ + state: 'created', + timeStamp: currentTime, + currentFrame: currentFrame + }); + this.processCallCount = 0; + } + + handleMessage(event) { + this.port.postMessage({ + message: event.data, + timeStamp: currentTime, + currentFrame: currentFrame, + processCallCount: this.processCallCount + }); + } + + process() { + ++this.processCallCount; + return true; + } +} + +registerProcessor('port-processor', PortProcessor); + +port.onmessage = (event) => port.postMessage(event.data); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/process-getter-test-instance-processor.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/process-getter-test-instance-processor.js new file mode 100644 index 000000000..b1434f54b --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/process-getter-test-instance-processor.js @@ -0,0 +1,44 @@ +/** + * @class ProcessGetterTestInstanceProcessor + * @extends AudioWorkletProcessor + * + * This processor class tests that a 'process' getter on an + * AudioWorkletProcessorConstructor instance is called at the right times. + */ + +class ProcessGetterTestInstanceProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this.getterCallCount = 0; + this.totalProcessCallCount = 0; + Object.defineProperty(this, 'process', { get: function() { + if (!(this instanceof ProcessGetterTestInstanceProcessor)) { + throw new Error('`process` getter called with bad `this`.'); + } + ++this.getterCallCount; + let functionCallCount = 0; + return () => { + if (++functionCallCount > 1) { + const message = 'Closure of function returned from `process` getter' + + ' should be used for only one call.' + this.port.postMessage({message: message}); + throw new Error(message); + } + if (++this.totalProcessCallCount < 2) { + return true; // Expect another getter call. + } + if (this.totalProcessCallCount != this.getterCallCount) { + const message = + 'Getter should be called only once for each process() call.' + this.port.postMessage({message: message}); + throw new Error(message); + } + this.port.postMessage({message: 'done'}); + return false; // No more calls required. + }; + }}); + } +} + +registerProcessor('process-getter-test-instance', + ProcessGetterTestInstanceProcessor); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/process-getter-test-prototype-processor.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/process-getter-test-prototype-processor.js new file mode 100644 index 000000000..cef5fa8b5 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/process-getter-test-prototype-processor.js @@ -0,0 +1,55 @@ +/** + * @class ProcessGetterTestPrototypeProcessor + * @extends AudioWorkletProcessor + * + * This processor class tests that a 'process' getter on + * AudioWorkletProcessorConstructor is called at the right times. + */ + +// Reporting errors during registerProcess() is awkward. +// The occurrance of an error is flagged, so that a trial registration can be +// performed and registration against the expected AudioWorkletNode name is +// performed only if no errors are flagged during the trial registration. +let error_flag = false; + +class ProcessGetterTestPrototypeProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this.getterCallCount = 0; + this.totalProcessCallCount = 0; + } + get process() { + if (!(this instanceof ProcessGetterTestPrototypeProcessor)) { + error_flag = true; + throw new Error('`process` getter called with bad `this`.'); + } + ++this.getterCallCount; + let functionCallCount = 0; + return () => { + if (++functionCallCount > 1) { + const message = 'Closure of function returned from `process` getter' + + ' should be used for only one call.' + this.port.postMessage({message: message}); + throw new Error(message); + } + if (++this.totalProcessCallCount < 2) { + return true; // Expect another getter call. + } + if (this.totalProcessCallCount != this.getterCallCount) { + const message = + 'Getter should be called only once for each process() call.' + this.port.postMessage({message: message}); + throw new Error(message); + } + this.port.postMessage({message: 'done'}); + return false; // No more calls required. + }; + } +} + +registerProcessor('trial-process-getter-test-prototype', + ProcessGetterTestPrototypeProcessor); +if (!error_flag) { + registerProcessor('process-getter-test-prototype', + ProcessGetterTestPrototypeProcessor); +} diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/process-parameter-test-processor.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/process-parameter-test-processor.js new file mode 100644 index 000000000..a300d3cde --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/process-parameter-test-processor.js @@ -0,0 +1,18 @@ +/** + * @class ProcessParameterTestProcessor + * @extends AudioWorkletProcessor + * + * This processor class forwards input and output parameters to its + * AudioWorkletNode. + */ +class ProcessParameterTestProcessor extends AudioWorkletProcessor { + process(inputs, outputs) { + this.port.postMessage({ + inputs: inputs, + outputs: outputs + }); + return false; + } +} + +registerProcessor('process-parameter-test', ProcessParameterTestProcessor); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/promise-processor.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/promise-processor.js new file mode 100644 index 000000000..6a8144b3c --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/promise-processor.js @@ -0,0 +1,40 @@ +/** + * @class PromiseProcessor + * @extends AudioWorkletProcessor + * + * This processor creates and resolves a promise in its `process` method. When + * the handler passed to `then()` is called, a counter that is global in the + * global scope is incremented. There are two copies of this + * AudioWorkletNode/Processor, so the counter should always be even in the + * process method of the AudioWorklet processing, since the Promise completion + * handler are resolved in between render quanta. + * + * After a few iterations of the test, one of the worklet posts back the string + * "ok" to the main thread, and the test is considered a success. + */ +var idx = 0; + +class PromiseProcessor extends AudioWorkletProcessor { + constructor(options) { + super(options); + } + + process(inputs, outputs) { + if (idx % 2 != 0) { + this.port.postMessage("ko"); + // Don't bother continuing calling process in this case, the test has + // already failed. + return false; + } + Promise.resolve().then(() => { + idx++; + if (idx == 100) { + this.port.postMessage("ok"); + } + }); + // Ensure process is called again. + return true; + } +} + +registerProcessor('promise-processor', PromiseProcessor); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/register-processor-typeerrors.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/register-processor-typeerrors.js new file mode 100644 index 000000000..93894842f --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/register-processor-typeerrors.js @@ -0,0 +1,39 @@ +// For cross-thread messaging. +class MessengerProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this.port.onmessage = this.startTest.bind(this); + } + + process() {} + + startTest(message) { + runRegisterProcessorTest(this.port); + } +} + +function runRegisterProcessorTest(messagePort) { + try { + // TypeError when a given parameter is not a Function. + const DummyObject = {}; + registerProcessor('type-error-on-object', DummyObject); + } catch (exception) { + messagePort.postMessage({ + name: exception.name, + message: exception.message + }); + } + + try { + // TypeError When a given parameter is a Function, but not a constructor. + const DummyFunction = () => {}; + registerProcessor('type-error-on-function', DummyFunction); + } catch (exception) { + messagePort.postMessage({ + name: exception.name, + message: exception.message + }); + } +} + +registerProcessor('messenger-processor', MessengerProcessor); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/rendersizehint-processor.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/rendersizehint-processor.js new file mode 100644 index 000000000..966096475 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/rendersizehint-processor.js @@ -0,0 +1,40 @@ +/** + * @class RenderSizeHintProcessor + * @extends AudioWorkletProcessor + * + * This processor class is used to verify that renderQuantumSize propagates + * correctly to the AudioWorkletGlobalScope and that the process() method + * receives buffers of the requested render quantum size. + */ +class RenderSizeHintProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this._processMessageSent = false; + + // Post the renderQuantumSize from AudioWorkletGlobalScope immediately + // upon construction. + this.port.postMessage({ + type: 'constructor', + renderQuantumSize: renderQuantumSize + }); + } + + process(inputs, outputs) { + if (!this._processMessageSent) { + // Verify the actual buffer length passed to process(). + // Use outputs[0][0].length as a safe fallback if inputs are + // unconnected. + const bufferLength = (inputs[0] && inputs[0][0]) + ? inputs[0][0].length + : outputs[0][0].length; + this.port.postMessage({ + type: 'process', + length: bufferLength + }); + this._processMessageSent = true; + } + return false; + } +} + +registerProcessor('rendersizehint-processor', RenderSizeHintProcessor); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/sharedarraybuffer-processor.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/sharedarraybuffer-processor.js new file mode 100644 index 000000000..2ccacccd4 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/sharedarraybuffer-processor.js @@ -0,0 +1,35 @@ +/** + * @class SharedArrayBufferProcessor + * @extends AudioWorkletProcessor + * + * This processor class demonstrates passing SharedArrayBuffers to and from + * workers. + */ +class SharedArrayBufferProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this.port.onmessage = this.handleMessage.bind(this); + this.port.onmessageerror = this.handleMessageError.bind(this); + let sab = new SharedArrayBuffer(8); + this.port.postMessage({state: 'created', sab}); + } + + handleMessage(event) { + this.port.postMessage({ + state: 'received message', + isSab: event.data instanceof SharedArrayBuffer + }); + } + + handleMessageError(event) { + this.port.postMessage({ + state: 'received messageerror' + }); + } + + process() { + return true; + } +} + +registerProcessor('sharedarraybuffer-processor', SharedArrayBufferProcessor); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/timing-info-processor.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/timing-info-processor.js new file mode 100644 index 000000000..714e32dbb --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/timing-info-processor.js @@ -0,0 +1,25 @@ +/** + * @class TimingInfoProcessor + * @extends AudioWorkletProcessor + * + * This processor class is to test the timing information in AWGS. + */ +class TimingInfoProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this.port.onmessage = this.echoMessage.bind(this); + } + + echoMessage(event) { + this.port.postMessage({ + currentTime: currentTime, + currentFrame: currentFrame + }); + } + + process() { + return true; + } +} + +registerProcessor('timing-info-processor', TimingInfoProcessor); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/zero-output-processor.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/zero-output-processor.js new file mode 100644 index 000000000..2d7399ca3 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/zero-output-processor.js @@ -0,0 +1,42 @@ +/** + * @class ZeroOutputProcessor + * @extends AudioWorkletProcessor + * + * This processor accumulates the incoming buffer and send the buffered data + * to the main thread when it reaches the specified frame length. The processor + * only supports the single input. + */ + +const kRenderQuantumFrames = 128; + +class ZeroOutputProcessor extends AudioWorkletProcessor { + constructor(options) { + super(); + + this._framesRequested = options.processorOptions.bufferLength; + this._framesCaptured = 0; + this._buffer = []; + for (let i = 0; i < options.processorOptions.channeCount; ++i) { + this._buffer[i] = new Float32Array(this._framesRequested); + } + } + + process(inputs) { + let input = inputs[0]; + let startIndex = this._framesCaptured; + let endIndex = startIndex + kRenderQuantumFrames; + for (let i = 0; i < this._buffer.length; ++i) { + this._buffer[i].subarray(startIndex, endIndex).set(input[i]); + } + this._framesCaptured = endIndex; + + if (this._framesCaptured >= this._framesRequested) { + this.port.postMessage({ capturedBuffer: this._buffer }); + return false; + } else { + return true; + } + } +} + +registerProcessor('zero-output-processor', ZeroOutputProcessor); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/zero-outputs-check-processor.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/zero-outputs-check-processor.js new file mode 100644 index 000000000..f816e918a --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/processors/zero-outputs-check-processor.js @@ -0,0 +1,78 @@ +/** + * Returns true if a given AudioPort is completely filled with zero samples. + * "AudioPort" is a short-hand for FrozenArray>. + * + * @param {FrozenArray>} audioPort + * @returns bool + */ +function IsAllZero(audioPort) { + for (let busIndex = 0; busIndex < audioPort.length; ++busIndex) { + const audioBus = audioPort[busIndex]; + for (let channelIndex = 0; channelIndex < audioBus.length; ++channelIndex) { + const audioChannel = audioBus[channelIndex]; + for (let sample = 0; sample < audioChannel.length; ++sample) { + if (audioChannel[sample] != 0) + return false; + } + } + } + return true; +} + +const kRenderQuantumFrames = 128; +const kTestLengthInSec = 1.0; +const kPulseDuration = 100; + +/** + * Checks the |outputs| argument of AudioWorkletProcessor.process() and + * send a message to an associated AudioWorkletNode. It needs to be all zero + * at all times. + * + * @class ZeroOutputsCheckProcessor + * @extends {AudioWorkletProcessor} + */ +class ZeroOutputsCheckProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this.startTime = currentTime; + this.counter = 0; + } + + process(inputs, outputs) { + if (!IsAllZero(outputs)) { + this.port.postMessage({ + type: 'assertion', + success: false, + message: 'Unexpected Non-zero sample found in |outputs|.' + }); + return false; + } + + if (currentTime - this.startTime >= kTestLengthInSec) { + this.port.postMessage({ + type: 'assertion', + success: true, + message: `|outputs| has been all zeros for ${kTestLengthInSec} ` + + 'seconds as expected.' + }); + return false; + } + + // Every ~0.25 second (100 render quanta), switch between outputting white + // noise and just exiting without doing anything. (from crbug.com/1099756) + this.counter++; + if (Math.floor(this.counter / kPulseDuration) % 2 == 0) + return true; + + let output = outputs[0]; + for (let channel = 0; channel < output.length; ++channel) { + for (let sample = 0; sample < 128; sample++) { + output[channel][sample] = 0.1 * (Math.random() - 0.5); + } + } + + return true; + } +} + +registerProcessor('zero-outputs-check-processor', ZeroOutputsCheckProcessor); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/simple-input-output.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/simple-input-output.https.html new file mode 100644 index 000000000..ac16b8268 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/simple-input-output.https.html @@ -0,0 +1,74 @@ + + + + + Test Simple AudioWorklet I/O + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/suspended-context-messageport.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/suspended-context-messageport.https.html new file mode 100644 index 000000000..53b1af032 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-audioworklet-interface/suspended-context-messageport.https.html @@ -0,0 +1,52 @@ + +Test MessagePort while AudioContext is not running + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/.gitkeep b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-allpass.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-allpass.html new file mode 100644 index 000000000..86618f9e4 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-allpass.html @@ -0,0 +1,42 @@ + + + + + biquad-allpass.html + + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-automation.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-automation.html new file mode 100644 index 000000000..d459d16fb --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-automation.html @@ -0,0 +1,406 @@ + + + + + Biquad Automation Test + + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-bandpass.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-bandpass.html new file mode 100644 index 000000000..166aa9b3c --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-bandpass.html @@ -0,0 +1,44 @@ + + + + + biquad-bandpass.html + + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-basic.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-basic.html new file mode 100644 index 000000000..4f8647493 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-basic.html @@ -0,0 +1,86 @@ + + + + + Test Basic BiquadFilterNode Properties + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-getFrequencyResponse.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-getFrequencyResponse.html new file mode 100644 index 000000000..23222e4df --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-getFrequencyResponse.html @@ -0,0 +1,394 @@ + + + + + Test BiquadFilter getFrequencyResponse() functionality + + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-highpass.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-highpass.html new file mode 100644 index 000000000..45c335bc4 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-highpass.html @@ -0,0 +1,42 @@ + + + + + biquad-highpass.html + + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-highshelf.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-highshelf.html new file mode 100644 index 000000000..345195f10 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-highshelf.html @@ -0,0 +1,43 @@ + + + + + biquad-highshelf.html + + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-lowpass.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-lowpass.html new file mode 100644 index 000000000..d20786e36 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-lowpass.html @@ -0,0 +1,45 @@ + + + + + biquad-lowpass.html + + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-lowshelf.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-lowshelf.html new file mode 100644 index 000000000..ab76cefd4 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-lowshelf.html @@ -0,0 +1,43 @@ + + + + + biquad-lowshelf.html + + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-notch.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-notch.html new file mode 100644 index 000000000..98e6e6e02 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-notch.html @@ -0,0 +1,43 @@ + + + + + biquad-notch.html + + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-peaking.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-peaking.html new file mode 100644 index 000000000..90b7c1546 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-peaking.html @@ -0,0 +1,46 @@ + + + + + biquad-peaking.html + + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-tail.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-tail.html new file mode 100644 index 000000000..3141bf7ff --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-tail.html @@ -0,0 +1,71 @@ + + + + + Test Biquad Tail Output + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquadfilter-rendersizehint.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquadfilter-rendersizehint.https.html new file mode 100644 index 000000000..7894eb1f4 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquadfilter-rendersizehint.https.html @@ -0,0 +1,16 @@ + +Test BiquadFilterNode with renderSizeHint + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquadfilternode-basic.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquadfilternode-basic.html new file mode 100644 index 000000000..7e71d0730 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/biquadfilternode-basic.html @@ -0,0 +1,64 @@ + + + + + biquadfilternode-basic.html + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/ctor-biquadfilter.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/ctor-biquadfilter.html new file mode 100644 index 000000000..652ee2565 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/ctor-biquadfilter.html @@ -0,0 +1,69 @@ + + + + + Test Constructor: BiquadFilter + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/no-dezippering.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/no-dezippering.html new file mode 100644 index 000000000..79dc27035 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-biquadfilternode-interface/no-dezippering.html @@ -0,0 +1,288 @@ + + + + + biquad-bandpass.html + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelmergernode-interface/.gitkeep b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelmergernode-interface/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelmergernode-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelmergernode-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelmergernode-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelmergernode-interface/active-processing.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelmergernode-interface/active-processing.https.html new file mode 100644 index 000000000..737462958 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelmergernode-interface/active-processing.https.html @@ -0,0 +1,88 @@ + + + + + Test Active Processing for ChannelMergerNode + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-basic.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-basic.html new file mode 100644 index 000000000..71a62f176 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-basic.html @@ -0,0 +1,67 @@ + + + + + audiochannelmerger-basic.html + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-disconnect.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-disconnect.html new file mode 100644 index 000000000..e8276ad36 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-disconnect.html @@ -0,0 +1,70 @@ + + + + + ChannelMergerNode: Asynchronous disconnect() correctly silences the + output + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-input-non-default.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-input-non-default.html new file mode 100644 index 000000000..98791b56a --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-input-non-default.html @@ -0,0 +1,71 @@ + + + + + ChannelMergerNode: Non-Default Input Handling + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-input.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-input.html new file mode 100644 index 000000000..c5728d45c --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-input.html @@ -0,0 +1,104 @@ + + + + audiochannelmerger-input.html + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelmergernode-interface/ctor-channelmerger.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelmergernode-interface/ctor-channelmerger.html new file mode 100644 index 000000000..5040a96ec --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelmergernode-interface/ctor-channelmerger.html @@ -0,0 +1,87 @@ + + + + + Test Constructor: ChannelMerger + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelsplitternode-interface/.gitkeep b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelsplitternode-interface/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelsplitternode-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelsplitternode-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelsplitternode-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelsplitternode-interface/audiochannelsplitter.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelsplitternode-interface/audiochannelsplitter.html new file mode 100644 index 000000000..9cb2ab5a4 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelsplitternode-interface/audiochannelsplitter.html @@ -0,0 +1,107 @@ + + + + + Tests AudioChannelSplitter + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelsplitternode-interface/ctor-channelsplitter.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelsplitternode-interface/ctor-channelsplitter.html new file mode 100644 index 000000000..d606d349a --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-channelsplitternode-interface/ctor-channelsplitter.html @@ -0,0 +1,105 @@ + + + + + Test Constructor: ChannelSplitter + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-constantsourcenode-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-constantsourcenode-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-constantsourcenode-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-constantsourcenode-interface/constant-source-basic.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-constantsourcenode-interface/constant-source-basic.html new file mode 100644 index 000000000..ce6621abe --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-constantsourcenode-interface/constant-source-basic.html @@ -0,0 +1,64 @@ + + + + Basic ConstantSourceNode Tests + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-constantsourcenode-interface/constant-source-onended.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-constantsourcenode-interface/constant-source-onended.html new file mode 100644 index 000000000..64bc54f21 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-constantsourcenode-interface/constant-source-onended.html @@ -0,0 +1,38 @@ + + + + + Test ConstantSourceNode onended + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-constantsourcenode-interface/constant-source-output.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-constantsourcenode-interface/constant-source-output.html new file mode 100644 index 000000000..5990376cf --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-constantsourcenode-interface/constant-source-output.html @@ -0,0 +1,207 @@ + + + + + Test ConstantSourceNode Output + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-constantsourcenode-interface/ctor-constantsource.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-constantsourcenode-interface/ctor-constantsource.html new file mode 100644 index 000000000..ea4a65e14 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-constantsourcenode-interface/ctor-constantsource.html @@ -0,0 +1,50 @@ + + + + + Test Constructor: ConstantSource + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-constantsourcenode-interface/test-constantsourcenode.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-constantsourcenode-interface/test-constantsourcenode.html new file mode 100644 index 000000000..9dd03ea11 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-constantsourcenode-interface/test-constantsourcenode.html @@ -0,0 +1,135 @@ + + +Test the ConstantSourceNode Interface + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/.gitkeep b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/active-processing.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/active-processing.https.html new file mode 100644 index 000000000..b0afc8641 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/active-processing.https.html @@ -0,0 +1,89 @@ + + + + + Test Active Processing for ConvolverNode + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolution-mono-mono.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolution-mono-mono.html new file mode 100644 index 000000000..570efebe2 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolution-mono-mono.html @@ -0,0 +1,62 @@ + + + + + convolution-mono-mono.html + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-cascade.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-cascade.html new file mode 100644 index 000000000..20bdfbdf4 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-cascade.html @@ -0,0 +1,61 @@ + + + + + Test Cascade of Mono Convolvers + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-channels.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-channels.html new file mode 100644 index 000000000..ac4f198d7 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-channels.html @@ -0,0 +1,43 @@ + + + + + Test Supported Number of Channels for ConvolverNode + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-rendersizehint.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-rendersizehint.https.html new file mode 100644 index 000000000..4af82cb8c --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-rendersizehint.https.html @@ -0,0 +1,21 @@ + +Test ConvolverNode with renderSizeHint + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-1-chan.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-1-chan.html new file mode 100644 index 000000000..e239a5e86 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-1-chan.html @@ -0,0 +1,406 @@ + + + + + Test Convolver Channel Outputs for Response with 1 channel + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-2-chan.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-2-chan.html new file mode 100644 index 000000000..a73eb3f8a --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-2-chan.html @@ -0,0 +1,373 @@ + + + + + Test Convolver Channel Outputs for Response with 2 channels + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-4-chan.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-4-chan.html new file mode 100644 index 000000000..f188d87b7 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-4-chan.html @@ -0,0 +1,508 @@ + + + + + Test Convolver Channel Outputs for Response with 4 channels + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-setBuffer-already-has-value.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-setBuffer-already-has-value.html new file mode 100644 index 000000000..ce2d5fcfe --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-setBuffer-already-has-value.html @@ -0,0 +1,51 @@ + + + + + convolver-setBuffer-already-has-value.html + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-setBuffer-null.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-setBuffer-null.html new file mode 100644 index 000000000..d35b8ec54 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-setBuffer-null.html @@ -0,0 +1,31 @@ + + + + + convolver-setBuffer-null.html + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-upmixing-1-channel-response.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-upmixing-1-channel-response.html new file mode 100644 index 000000000..b0b3a5965 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/convolver-upmixing-1-channel-response.html @@ -0,0 +1,143 @@ + +Test that up-mixing signals in ConvolverNode processing is linear + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/ctor-convolver.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/ctor-convolver.html new file mode 100644 index 000000000..0bbb771c8 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/ctor-convolver.html @@ -0,0 +1,147 @@ + + + + ConvolverNode Constructor + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/realtime-conv.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/realtime-conv.html new file mode 100644 index 000000000..a84e2622a --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/realtime-conv.html @@ -0,0 +1,144 @@ + + + + + Test Convolver on Real-time Context + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/transferred-buffer-output.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/transferred-buffer-output.html new file mode 100644 index 000000000..e37a98c38 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-convolvernode-interface/transferred-buffer-output.html @@ -0,0 +1,107 @@ + + + + + Test Convolver Output with Transferred Buffer + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/.gitkeep b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/ctor-delay.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/ctor-delay.html new file mode 100644 index 000000000..e7ccefc65 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/ctor-delay.html @@ -0,0 +1,76 @@ + + + + + Test Constructor: Delay + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/delay-test.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/delay-test.html new file mode 100644 index 000000000..6277c253e --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/delay-test.html @@ -0,0 +1,61 @@ + + + + Test DelayNode Delay + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/delaynode-channel-count-1.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/delaynode-channel-count-1.html new file mode 100644 index 000000000..dd964ef9e --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/delaynode-channel-count-1.html @@ -0,0 +1,104 @@ + +Test that DelayNode output channelCount matches that of the delayed input + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/delaynode-max-default-delay.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/delaynode-max-default-delay.html new file mode 100644 index 000000000..ef526c96f --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/delaynode-max-default-delay.html @@ -0,0 +1,49 @@ + + + + + delaynode-max-default-delay.html + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/delaynode-max-nondefault-delay.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/delaynode-max-nondefault-delay.html new file mode 100644 index 000000000..3be07255e --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/delaynode-max-nondefault-delay.html @@ -0,0 +1,51 @@ + + + + + delaynode-max-nondefault-delay.html + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/delaynode-maxdelay.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/delaynode-maxdelay.html new file mode 100644 index 000000000..a43ceeb7b --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/delaynode-maxdelay.html @@ -0,0 +1,54 @@ + + + + + delaynode-maxdelay.html + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/delaynode-maxdelaylimit.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/delaynode-maxdelaylimit.html new file mode 100644 index 000000000..caf2f85df --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/delaynode-maxdelaylimit.html @@ -0,0 +1,68 @@ + + + + + delaynode-maxdelaylimit.html + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/delaynode-scheduling.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/delaynode-scheduling.html new file mode 100644 index 000000000..af6c54950 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/delaynode-scheduling.html @@ -0,0 +1,51 @@ + + + + + delaynode-scheduling.html + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/delaynode.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/delaynode.html new file mode 100644 index 000000000..da508e439 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/delaynode.html @@ -0,0 +1,61 @@ + + + + + delaynode.html + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/maxdelay-rounding.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/maxdelay-rounding.html new file mode 100644 index 000000000..cce052d0c --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/maxdelay-rounding.html @@ -0,0 +1,65 @@ + + + + + Test DelayNode when maxDelayTime requires rounding + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/no-dezippering.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/no-dezippering.html new file mode 100644 index 000000000..ccca103a3 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-delaynode-interface/no-dezippering.html @@ -0,0 +1,184 @@ + + + + + Test DelayNode Has No Dezippering + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-destinationnode-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-destinationnode-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-destinationnode-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-destinationnode-interface/destination.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-destinationnode-interface/destination.html new file mode 100644 index 000000000..1af0e0f01 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-destinationnode-interface/destination.html @@ -0,0 +1,51 @@ + + + + + AudioDestinationNode + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-dynamicscompressornode-interface/.gitkeep b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-dynamicscompressornode-interface/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-dynamicscompressornode-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-dynamicscompressornode-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-dynamicscompressornode-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-dynamicscompressornode-interface/ctor-dynamicscompressor.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-dynamicscompressornode-interface/ctor-dynamicscompressor.html new file mode 100644 index 000000000..5306e9428 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-dynamicscompressornode-interface/ctor-dynamicscompressor.html @@ -0,0 +1,137 @@ + + + + DynamicsCompressorNode Constructor + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-dynamicscompressornode-interface/dynamicscompressor-basic.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-dynamicscompressornode-interface/dynamicscompressor-basic.html new file mode 100644 index 000000000..6c602010d --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-dynamicscompressornode-interface/dynamicscompressor-basic.html @@ -0,0 +1,48 @@ + + + + + dynamicscompressor-basic.html + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-gainnode-interface/.gitkeep b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-gainnode-interface/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-gainnode-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-gainnode-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-gainnode-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-gainnode-interface/ctor-gain.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-gainnode-interface/ctor-gain.html new file mode 100644 index 000000000..dcab1aa0d --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-gainnode-interface/ctor-gain.html @@ -0,0 +1,54 @@ + + + + + Test Constructor: Gain + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-gainnode-interface/gain-basic.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-gainnode-interface/gain-basic.html new file mode 100644 index 000000000..de2ba11a7 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-gainnode-interface/gain-basic.html @@ -0,0 +1,37 @@ + + + + + + gain-basic.html + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-gainnode-interface/gain.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-gainnode-interface/gain.html new file mode 100644 index 000000000..1bae59035 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-gainnode-interface/gain.html @@ -0,0 +1,130 @@ + + + + + Basic GainNode Functionality + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-gainnode-interface/no-dezippering.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-gainnode-interface/no-dezippering.html new file mode 100644 index 000000000..f6bb8299b --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-gainnode-interface/no-dezippering.html @@ -0,0 +1,105 @@ + + + + + Gain Dezippering Test: Dezippering Removed + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-iirfilternode-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-iirfilternode-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-iirfilternode-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-iirfilternode-interface/ctor-iirfilter.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-iirfilternode-interface/ctor-iirfilter.html new file mode 100644 index 000000000..4336f0034 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-iirfilternode-interface/ctor-iirfilter.html @@ -0,0 +1,107 @@ + + + + Test Constructor: IIRFilter + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-iirfilternode-interface/iir-filter-silent-block-crash.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-iirfilternode-interface/iir-filter-silent-block-crash.html new file mode 100644 index 000000000..9148ac30d --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-iirfilternode-interface/iir-filter-silent-block-crash.html @@ -0,0 +1,9 @@ + + +Regression test for IIRFilter destination crash + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-basic.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-basic.html new file mode 100644 index 000000000..7828f0522 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-basic.html @@ -0,0 +1,204 @@ + + + + + Test Basic IIRFilterNode Properties + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-getFrequencyResponse.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-getFrequencyResponse.html new file mode 100644 index 000000000..467fe6188 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-getFrequencyResponse.html @@ -0,0 +1,137 @@ + + + + + Test IIRFilter getFrequencyResponse() functionality + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-normalization-precision.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-normalization-precision.html new file mode 100644 index 000000000..e224111b7 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-normalization-precision.html @@ -0,0 +1,41 @@ + + + + + Test IIRFilter coefficient normalization precision + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter.html new file mode 100644 index 000000000..aa38a6bfc --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter.html @@ -0,0 +1,572 @@ + + + + + Test Basic IIRFilterNode Operation + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-iirfilternode-interface/test-iirfilternode.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-iirfilternode-interface/test-iirfilternode.html new file mode 100644 index 000000000..001a2a617 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-iirfilternode-interface/test-iirfilternode.html @@ -0,0 +1,59 @@ + + +Test the IIRFilterNode Interface + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/.gitkeep b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/cors-check.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/cors-check.https.html new file mode 100644 index 000000000..38bd94a03 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/cors-check.https.html @@ -0,0 +1,76 @@ + + + + + Test if MediaElementAudioSourceNode works for cross-origin redirects with + "cors" request mode. + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSource-mediaStreamAudioDestination-stream-crash.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSource-mediaStreamAudioDestination-stream-crash.html new file mode 100644 index 000000000..40bf34c75 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSource-mediaStreamAudioDestination-stream-crash.html @@ -0,0 +1,8 @@ + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html new file mode 100644 index 000000000..39d238ec2 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html @@ -0,0 +1,130 @@ + + + + + + + MediaElementAudioSource interface test (to scriptProcessor) + + + + + + +
+ + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSource_closed_context-crash.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSource_closed_context-crash.html new file mode 100644 index 000000000..88753f220 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSource_closed_context-crash.html @@ -0,0 +1,9 @@ + + +Regression for MediaElementAudioSourceNode constructor crash after closing AudioContext + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSource_volumeChange.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSource_volumeChange.html new file mode 100644 index 000000000..efeba6874 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSource_volumeChange.html @@ -0,0 +1,121 @@ + + + + + MediaElementAudioSourceNode reflects HTMLMediaElement effective volume changes + + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/no-cors.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/no-cors.https.html new file mode 100644 index 000000000..de2f0b7dd --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/no-cors.https.html @@ -0,0 +1,75 @@ + + + + + Test if MediaElementAudioSourceNode works for cross-origin redirects with + "no-cors" request mode. + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/setSinkId-with-MediaElementAudioSourceNode.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/setSinkId-with-MediaElementAudioSourceNode.https.html new file mode 100644 index 000000000..af7178271 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/setSinkId-with-MediaElementAudioSourceNode.https.html @@ -0,0 +1,49 @@ + + +Test HTMLMediaElement.setSinkId() with MediaElementAudioSourceNode + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiodestinationnode-interface/.gitkeep b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiodestinationnode-interface/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiodestinationnode-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiodestinationnode-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiodestinationnode-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiodestinationnode-interface/closed-audiocontext-construction.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiodestinationnode-interface/closed-audiocontext-construction.html new file mode 100644 index 000000000..23bc9dc81 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiodestinationnode-interface/closed-audiocontext-construction.html @@ -0,0 +1,21 @@ + +MediaStreamAudioDestinationNode after closing AudioContext + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiodestinationnode-interface/ctor-mediastreamaudiodestination.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiodestinationnode-interface/ctor-mediastreamaudiodestination.html new file mode 100644 index 000000000..7d67c1e68 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiodestinationnode-interface/ctor-mediastreamaudiodestination.html @@ -0,0 +1,62 @@ + + + + MediaStreamAudioDestinationNode Constructor + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/.gitkeep b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-ctor.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-ctor.html new file mode 100644 index 000000000..a71141965 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-ctor.html @@ -0,0 +1,73 @@ + + + + + MediaStreamAudioSourceNode + + + + +
+ + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-from-context-with-different-rate.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-from-context-with-different-rate.https.html new file mode 100644 index 000000000..486047e2e --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-from-context-with-different-rate.https.html @@ -0,0 +1,562 @@ + + + +Connecting to MediaStreamAudioSourceNode from nodes in different rates + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-routing.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-routing.html new file mode 100644 index 000000000..816eba0b2 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-routing.html @@ -0,0 +1,127 @@ + + + + + MediaStreamAudioSourceNode + + + + +
+ + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/silence-detector.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/silence-detector.js new file mode 100644 index 000000000..3d76ffc98 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/silence-detector.js @@ -0,0 +1,49 @@ +// AudioWorkletProcessor that detects silence and notifies the main thread on state change. +class SilenceDetector extends AudioWorkletProcessor { + constructor() { + super(); + // Assume silence and no input until the first buffer is processed. + this.isSilent = true; + this.hasInput = false; + } + + process(inputs, outputs, parameters) { + const input = inputs[0]; + const currentHasInput = input && input.length > 0; + + // Detect silence state (no input counts as silence) + let isCurrentlySilent = true; + if (currentHasInput) { + const channel = input[0]; + for (let i = 0; i < channel.length; i++) { + if (channel[i] !== 0) { + isCurrentlySilent = false; + break; + } + } + } + + // Check if state changed + const hasInputChanged = this.hasInput !== currentHasInput; + const isSilentChanged = this.isSilent !== isCurrentlySilent; + + // Update state + this.hasInput = currentHasInput; + this.isSilent = isCurrentlySilent; + + // Send notifications + if (hasInputChanged || isSilentChanged) { + this.port.postMessage({ + type: "stateChanged", + isSilent: this.isSilent, + hasInput: this.hasInput, + hasInputChanged: hasInputChanged, + isSilentChanged: isSilentChanged, + }); + } + + return currentHasInput; + } +} + +registerProcessor("silence-detector", SilenceDetector); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-offlineaudiocontext-interface/.gitkeep b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-offlineaudiocontext-interface/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-offlineaudiocontext-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-offlineaudiocontext-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..e7da88c82 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-offlineaudiocontext-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: offline-audio-context + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-offlineaudiocontext-interface/ctor-offlineaudiocontext.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-offlineaudiocontext-interface/ctor-offlineaudiocontext.html new file mode 100644 index 000000000..4b6863103 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-offlineaudiocontext-interface/ctor-offlineaudiocontext.html @@ -0,0 +1,203 @@ + + + + Test Constructor: OfflineAudioContext + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-offlineaudiocontext-interface/current-time-block-size.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-offlineaudiocontext-interface/current-time-block-size.html new file mode 100644 index 000000000..ee976f7f7 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-offlineaudiocontext-interface/current-time-block-size.html @@ -0,0 +1,17 @@ + +Test currentTime at completion of OfflineAudioContext rendering + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-offlineaudiocontext-interface/offlineaudiocontext-detached-execution-context.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-offlineaudiocontext-interface/offlineaudiocontext-detached-execution-context.html new file mode 100644 index 000000000..6eafd15fd --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-offlineaudiocontext-interface/offlineaudiocontext-detached-execution-context.html @@ -0,0 +1,34 @@ + + + + + Testing behavior OfflineAudioContext after execution context is detached + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-offlineaudiocontext-interface/offlineaudiocontext-rendersizehint.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-offlineaudiocontext-interface/offlineaudiocontext-rendersizehint.html new file mode 100644 index 000000000..91195de84 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-offlineaudiocontext-interface/offlineaudiocontext-rendersizehint.html @@ -0,0 +1,8 @@ + +Test OfflineAudioContextOptions renderSizeHint + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-offlineaudiocontext-interface/offlineaudiocontext-suspend-rendersizehint.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-offlineaudiocontext-interface/offlineaudiocontext-suspend-rendersizehint.https.html new file mode 100644 index 000000000..a5e5a5b34 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-offlineaudiocontext-interface/offlineaudiocontext-suspend-rendersizehint.https.html @@ -0,0 +1,28 @@ + +Test OfflineAudioContext suspend with renderSizeHint + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-offlineaudiocontext-interface/startrendering-after-discard.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-offlineaudiocontext-interface/startrendering-after-discard.html new file mode 100644 index 000000000..dd610ec33 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-offlineaudiocontext-interface/startrendering-after-discard.html @@ -0,0 +1,24 @@ + +Test for rejected promise from startRendering() on an + OfflineAudioContext in a discarded browsing context + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-oscillatornode-interface/.gitkeep b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-oscillatornode-interface/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-oscillatornode-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-oscillatornode-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-oscillatornode-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-oscillatornode-interface/crashtests/stop-before-start.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-oscillatornode-interface/crashtests/stop-before-start.html new file mode 100644 index 000000000..89d22c0d1 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-oscillatornode-interface/crashtests/stop-before-start.html @@ -0,0 +1,16 @@ + + + + Test stop() time before start() time on OscillatorNode with AudioParam + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-oscillatornode-interface/ctor-oscillator.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-oscillatornode-interface/ctor-oscillator.html new file mode 100644 index 000000000..bf50195a5 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-oscillatornode-interface/ctor-oscillator.html @@ -0,0 +1,112 @@ + + + + + Test Constructor: Oscillator + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-oscillatornode-interface/detune-limiting.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-oscillatornode-interface/detune-limiting.html new file mode 100644 index 000000000..e3e6d40ed --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-oscillatornode-interface/detune-limiting.html @@ -0,0 +1,113 @@ + + + + Oscillator Detune: High Detune Limits and Automation + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-oscillatornode-interface/detune-overflow.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-oscillatornode-interface/detune-overflow.html new file mode 100644 index 000000000..28c28bc1d --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-oscillatornode-interface/detune-overflow.html @@ -0,0 +1,41 @@ + + + + Test Osc.detune Overflow + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-oscillatornode-interface/osc-basic-waveform.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-oscillatornode-interface/osc-basic-waveform.html new file mode 100644 index 000000000..ce6e262fa --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-oscillatornode-interface/osc-basic-waveform.html @@ -0,0 +1,229 @@ + + + + + Test Basic Oscillator Sine Wave Test + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/.gitkeep b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/automation-changes.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/automation-changes.html new file mode 100644 index 000000000..676a186e8 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/automation-changes.html @@ -0,0 +1,135 @@ + + + + Panner Node Automation + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/ctor-panner.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/ctor-panner.html new file mode 100644 index 000000000..c434aa8c6 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/ctor-panner.html @@ -0,0 +1,468 @@ + + + + + Test Constructor: Panner + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/distance-exponential.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/distance-exponential.html new file mode 100644 index 000000000..383e2c67b --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/distance-exponential.html @@ -0,0 +1,34 @@ + + + + + distance-exponential.html + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/distance-inverse.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/distance-inverse.html new file mode 100644 index 000000000..a4ff984e0 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/distance-inverse.html @@ -0,0 +1,28 @@ + + + + + distance-inverse.html + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/distance-linear.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/distance-linear.html new file mode 100644 index 000000000..812fea3eb --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/distance-linear.html @@ -0,0 +1,30 @@ + + + + + distance-linear.html + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/offline-hrtf-active-immediately.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/offline-hrtf-active-immediately.html new file mode 100644 index 000000000..f89a6da3d --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/offline-hrtf-active-immediately.html @@ -0,0 +1,47 @@ + + + + Test offline HRTF PannerNode is effective before rendering + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/panner-automation-basic.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/panner-automation-basic.html new file mode 100644 index 000000000..5c3df0e6f --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/panner-automation-basic.html @@ -0,0 +1,298 @@ + + + + + Test Basic PannerNode with Automation Position Properties + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/panner-automation-equalpower-stereo.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/panner-automation-equalpower-stereo.html new file mode 100644 index 000000000..7afc9c2a3 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/panner-automation-equalpower-stereo.html @@ -0,0 +1,47 @@ + + + + + panner-automation-equalpower-stereo.html + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/panner-automation-position.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/panner-automation-position.html new file mode 100644 index 000000000..8e09e869a --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/panner-automation-position.html @@ -0,0 +1,265 @@ + + + + + Test Automation of PannerNode Positions + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/panner-azimuth.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/panner-azimuth.html new file mode 100644 index 000000000..d09f2ec35 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/panner-azimuth.html @@ -0,0 +1,51 @@ + + + + Test Panner Azimuth Calculation + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping.html new file mode 100644 index 000000000..78c1ec6dc --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping.html @@ -0,0 +1,227 @@ + + + + + Test Clamping of Distance for PannerNode + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/panner-equalpower-stereo.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/panner-equalpower-stereo.html new file mode 100644 index 000000000..2a0225b3f --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/panner-equalpower-stereo.html @@ -0,0 +1,44 @@ + + + + + panner-equalpower-stereo.html + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/panner-equalpower.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/panner-equalpower.html new file mode 100644 index 000000000..7009ca08e --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/panner-equalpower.html @@ -0,0 +1,109 @@ + + + + + panner-equalpower.html + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/panner-rolloff-clamping.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/panner-rolloff-clamping.html new file mode 100644 index 000000000..288f5d0b2 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/panner-rolloff-clamping.html @@ -0,0 +1,80 @@ + + + + + Test Clamping of PannerNode rolloffFactor + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/pannernode-basic.window.js b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/pannernode-basic.window.js new file mode 100644 index 000000000..298fce0f2 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/pannernode-basic.window.js @@ -0,0 +1,71 @@ +test((t) => { + const context = new AudioContext(); + const source = new ConstantSourceNode(context); + const panner = new PannerNode(context); + source.connect(panner).connect(context.destination); + + // Basic parameters + assert_equals(panner.numberOfInputs,1); + assert_equals(panner.numberOfOutputs,1); + assert_equals(panner.refDistance, 1); + panner.refDistance = 270.5; + assert_equals(panner.refDistance, 270.5); + assert_equals(panner.maxDistance, 10000); + panner.maxDistance = 100.5; + assert_equals(panner.maxDistance, 100.5); + assert_equals(panner.rolloffFactor, 1); + panner.rolloffFactor = 0.75; + assert_equals(panner.rolloffFactor, 0.75); + assert_equals(panner.coneInnerAngle, 360); + panner.coneInnerAngle = 240.5; + assert_equals(panner.coneInnerAngle, 240.5); + assert_equals(panner.coneOuterAngle, 360); + panner.coneOuterAngle = 166.5; + assert_equals(panner.coneOuterAngle, 166.5); + assert_equals(panner.coneOuterGain, 0); + panner.coneOuterGain = 0.25; + assert_equals(panner.coneOuterGain, 0.25); + assert_equals(panner.panningModel, 'equalpower'); + assert_equals(panner.distanceModel, 'inverse'); + + // Position/orientation AudioParams + assert_equals(panner.positionX.value, 0); + assert_equals(panner.positionY.value, 0); + assert_equals(panner.positionZ.value, 0); + assert_equals(panner.orientationX.value, 1); + assert_equals(panner.orientationY.value, 0); + assert_equals(panner.orientationZ.value, 0); + + // AudioListener + assert_equals(context.listener.positionX.value, 0); + assert_equals(context.listener.positionY.value, 0); + assert_equals(context.listener.positionZ.value, 0); + assert_equals(context.listener.forwardX.value, 0); + assert_equals(context.listener.forwardY.value, 0); + assert_equals(context.listener.forwardZ.value, -1); + assert_equals(context.listener.upX.value, 0); + assert_equals(context.listener.upY.value, 1); + assert_equals(context.listener.upZ.value, 0); + + panner.panningModel = 'equalpower'; + assert_equals(panner.panningModel, 'equalpower'); + panner.panningModel = 'HRTF'; + assert_equals(panner.panningModel, 'HRTF'); + panner.panningModel = 'invalid'; + assert_equals(panner.panningModel, 'HRTF'); + + // Check that numerical values are no longer supported. We shouldn't + // throw and the value shouldn't be changed. + panner.panningModel = 1; + assert_equals(panner.panningModel, 'HRTF'); + + panner.distanceModel = 'linear'; + assert_equals(panner.distanceModel, 'linear'); + panner.distanceModel = 'inverse'; + assert_equals(panner.distanceModel, 'inverse'); + panner.distanceModel = 'exponential'; + assert_equals(panner.distanceModel, 'exponential'); + + panner.distanceModel = 'invalid'; + assert_equals(panner.distanceModel, 'exponential'); +}, 'Test the PannerNode interface'); diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/pannernode-setposition-throws.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/pannernode-setposition-throws.html new file mode 100644 index 000000000..a1c3aa9a7 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/pannernode-setposition-throws.html @@ -0,0 +1,73 @@ + + +Test PannerNode.setPosition() throws with parameter out of range of float + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/test-pannernode-automation.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/test-pannernode-automation.html new file mode 100644 index 000000000..ce474b10b --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-pannernode-interface/test-pannernode-automation.html @@ -0,0 +1,36 @@ + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-periodicwave-interface/.gitkeep b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-periodicwave-interface/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-periodicwave-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-periodicwave-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-periodicwave-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-periodicwave-interface/createPeriodicWaveInfiniteValuesThrows.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-periodicwave-interface/createPeriodicWaveInfiniteValuesThrows.html new file mode 100644 index 000000000..928f45bd8 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-periodicwave-interface/createPeriodicWaveInfiniteValuesThrows.html @@ -0,0 +1,22 @@ + + +Test AudioContext.createPeriodicWave when inputs contain Infinite values + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-periodicwave-interface/periodicWave.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-periodicwave-interface/periodicWave.html new file mode 100644 index 000000000..fe42f8ad5 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-periodicwave-interface/periodicWave.html @@ -0,0 +1,130 @@ + + + + + Test Constructor: PeriodicWave + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-scriptprocessornode-interface/.gitkeep b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-scriptprocessornode-interface/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-scriptprocessornode-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-scriptprocessornode-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-scriptprocessornode-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-scriptprocessornode-interface/scriptprocessor-rendersizehint.https.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-scriptprocessornode-interface/scriptprocessor-rendersizehint.https.html new file mode 100644 index 000000000..adecfac8c --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-scriptprocessornode-interface/scriptprocessor-rendersizehint.https.html @@ -0,0 +1,39 @@ + +Test ScriptProcessorNode with renderSizeHint + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-scriptprocessornode-interface/simple-input-output.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-scriptprocessornode-interface/simple-input-output.html new file mode 100644 index 000000000..1bbe3303a --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-scriptprocessornode-interface/simple-input-output.html @@ -0,0 +1,84 @@ + + + + Test ScriptProcessorNode + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-stereopanner-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-stereopanner-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-stereopanner-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-stereopanner-interface/ctor-stereopanner.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-stereopanner-interface/ctor-stereopanner.html new file mode 100644 index 000000000..9409f1ffc --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-stereopanner-interface/ctor-stereopanner.html @@ -0,0 +1,131 @@ + + + + + Test Constructor: StereoPanner + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-stereopanner-interface/no-dezippering.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-stereopanner-interface/no-dezippering.html new file mode 100644 index 000000000..355db8b9d --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-stereopanner-interface/no-dezippering.html @@ -0,0 +1,261 @@ + + + + + Test StereoPannerNode Has No Dezippering + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-stereopanner-interface/stereopannernode-basic.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-stereopanner-interface/stereopannernode-basic.html new file mode 100644 index 000000000..48bacb08c --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-stereopanner-interface/stereopannernode-basic.html @@ -0,0 +1,54 @@ + + + + + stereopannernode-basic.html + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-stereopanner-interface/stereopannernode-panning.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-stereopanner-interface/stereopannernode-panning.html new file mode 100644 index 000000000..f683fd78b --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-stereopanner-interface/stereopannernode-panning.html @@ -0,0 +1,34 @@ + + + + + stereopannernode-panning.html + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/.gitkeep b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/WEB_FEATURES.yml b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/WEB_FEATURES.yml new file mode 100644 index 000000000..51e62e2c9 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: web-audio + files: "**" diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/ctor-waveshaper.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/ctor-waveshaper.html new file mode 100644 index 000000000..7aa33ca5a --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/ctor-waveshaper.html @@ -0,0 +1,72 @@ + + + + + Test Constructor: WaveShaper + + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/curve-tests.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/curve-tests.html new file mode 100644 index 000000000..d09cf78fd --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/curve-tests.html @@ -0,0 +1,184 @@ + + + + WaveShaperNode interface - Curve tests | WebAudio + + + + + +
+
+ + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/silent-inputs.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/silent-inputs.html new file mode 100644 index 000000000..606930337 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/silent-inputs.html @@ -0,0 +1,77 @@ + + + + + Test Silent Inputs to WaveShaperNode + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/waveshaper-copy-curve.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/waveshaper-copy-curve.html new file mode 100644 index 000000000..a47b566ea --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/waveshaper-copy-curve.html @@ -0,0 +1,80 @@ + + + + + Test WaveShaper Copies Curve Data + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/waveshaper-limits.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/waveshaper-limits.html new file mode 100644 index 000000000..9ac196a27 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/waveshaper-limits.html @@ -0,0 +1,96 @@ + + + + + waveshaper-limits.html + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/waveshaper-simple.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/waveshaper-simple.html new file mode 100644 index 000000000..affd0c58a --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/waveshaper-simple.html @@ -0,0 +1,61 @@ + + + + + Simple Tests of WaveShaperNode + + + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/waveshaper.html b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/waveshaper.html new file mode 100644 index 000000000..d0725f4b7 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/webaudio/the-audio-api/the-waveshapernode-interface/waveshaper.html @@ -0,0 +1,133 @@ + + + + + waveshaper.html + + + + + + + + diff --git a/packages/react-native-audio-api/wpt_tests/wpt-api.js b/packages/react-native-audio-api/wpt_tests/wpt-api.js new file mode 100644 index 000000000..5e2537e50 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/wpt-api.js @@ -0,0 +1,63 @@ +'use strict'; + +/** + * Slim Web Audio API surface for the Node WPT harness. + * Only spec-defined classes are exported — no RN extensions + * (recorder, decoder, streamer, worklet nodes, etc.). + */ + +const path = require('node:path'); + +const packageRoot = path.resolve(__dirname, '..'); + +function loadDefault(relativePath) { + const mod = require(path.join(packageRoot, relativePath)); + return mod.default ?? mod; +} + +const WEB_AUDIO_CLASSES = [ + 'AnalyserNode', + 'AudioBuffer', + 'AudioBufferSourceNode', + 'AudioContext', + 'AudioDestinationNode', + 'AudioNode', + 'AudioParam', + 'AudioScheduledSourceNode', + 'BaseAudioContext', + 'BiquadFilterNode', + 'ConstantSourceNode', + 'ConvolverNode', + 'DelayNode', + 'GainNode', + 'IIRFilterNode', + 'OfflineAudioContext', + 'OscillatorNode', + 'PeriodicWave', + 'StereoPannerNode', + 'WaveShaperNode', +]; + +const api = {}; + +for (const name of WEB_AUDIO_CLASSES) { + try { + api[name] = loadDefault(`lib/commonjs/core/${name}`); + } catch (error) { + throw new Error( + `Failed to load ${name} for WPT (${error.message}). Run yarn build first.`, + { cause: error } + ); + } +} + +const errors = require(path.join(packageRoot, 'lib/commonjs/errors')); +Object.assign(api, { + AudioApiError: errors.AudioApiError, + IndexSizeError: errors.IndexSizeError, + InvalidAccessError: errors.InvalidAccessError, + InvalidStateError: errors.InvalidStateError, + NotSupportedError: errors.NotSupportedError, +}); + +module.exports = api; diff --git a/packages/react-native-audio-api/wpt_tests/wpt/WptParallelRunner.mjs b/packages/react-native-audio-api/wpt_tests/wpt/WptParallelRunner.mjs new file mode 100644 index 000000000..2a8c42a33 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/wpt/WptParallelRunner.mjs @@ -0,0 +1,263 @@ +import { fork } from 'node:child_process'; +import path from 'node:path'; + +import chalk from 'chalk'; +import wptRunner from 'wpt-runner'; + +import { + createReporter, + createWptEnvironment, + groupTestsByClass, + normalizeTestPath, + printSummary, + rootURL, + testsPath, +} from './wpt-shared.mjs'; + +const workerScriptPath = path.join( + path.dirname(new URL(import.meta.url).pathname), + 'wpt-worker.mjs' +); + +/** + * Runs independent WPT test classes in separate child processes. + * Each worker loads its own JSI/native runtime and executes one test class + * (interface directory) at a time from a shared queue. + */ +export class WptParallelRunner { + #jobs; + #handlers; + #numPass = 0; + #numFail = 0; + #timerStarted = false; + #summaryPrinted = false; + #queue = []; + #activeWorkers = 0; + #nextWorkerId = 0; + #resolveRun; + #rejectRun; + /** @type {Map} */ + #workerState = new Map(); + + constructor({ jobs, handlers = {} }) { + if (!Number.isFinite(jobs) || jobs < 1) { + throw new Error(`WptParallelRunner requires jobs >= 1, got ${jobs}`); + } + this.#jobs = jobs; + this.#handlers = handlers; + } + + async run(testPaths) { + const normalizedPaths = testPaths.map(normalizeTestPath); + this.#queue = groupTestsByClass(normalizedPaths); + + if (this.#queue.length === 0) { + return { numPass: 0, numFail: 0 }; + } + + const workerCount = Math.min(this.#jobs, this.#queue.length); + console.log( + chalk.dim( + `Running ${normalizedPaths.length} files in ${this.#queue.length} test classes ` + + `using ${workerCount} worker process(es).` + ) + ); + + return new Promise((resolve, reject) => { + this.#resolveRun = resolve; + this.#rejectRun = reject; + + for (let i = 0; i < workerCount; i += 1) { + this.#spawnWorker(); + } + }); + } + + printSummary() { + if (this.#summaryPrinted) { + return; + } + this.#summaryPrinted = true; + printSummary({ + numPass: this.#numPass, + numFail: this.#numFail, + timerStarted: this.#timerStarted, + }); + } + + markTimerStarted() { + this.#timerStarted = true; + } + + getCounts() { + return { numPass: this.#numPass, numFail: this.#numFail }; + } + + #spawnWorker() { + const workerId = this.#nextWorkerId; + this.#nextWorkerId += 1; + + const child = fork(workerScriptPath, [], { + stdio: ['inherit', 'inherit', 'inherit', 'ipc'], + env: { + ...process.env, + WPT_WORKER_ID: String(workerId), + }, + }); + + this.#activeWorkers += 1; + this.#workerState.set(workerId, { child, busy: false, assignment: null }); + + child.on('message', message => { + this.#handleWorkerMessage(workerId, message); + }); + + child.on('error', error => { + if (this.#rejectRun != null) { + const reject = this.#rejectRun; + this.#resolveRun = null; + this.#rejectRun = null; + reject(error); + } + }); + + child.on('exit', (code, signal) => { + const state = this.#workerState.get(workerId); + const assignment = state?.assignment ?? null; + const wasBusy = state?.busy === true; + + this.#activeWorkers -= 1; + this.#workerState.delete(workerId); + + if (signal != null && this.#rejectRun != null) { + const reject = this.#rejectRun; + this.#resolveRun = null; + this.#rejectRun = null; + reject(new Error(`WPT worker ${workerId} exited due to signal ${signal}`)); + return; + } + + if (code !== 0 && wasBusy) { + this.#numFail += 1; + console.error( + chalk.red( + `WPT worker ${workerId} crashed while running a test class (exit code ${code}).` + ) + ); + if (assignment != null) { + this.#queue.unshift(assignment); + } + } + + if (this.#queue.length > 0 && this.#workerState.size < this.#jobs) { + this.#spawnWorker(); + } + + this.#maybeFinishRun(); + }); + + this.#dispatchNext(workerId); + } + + #dispatchNext(workerId) { + const state = this.#workerState.get(workerId); + if (state == null) { + return; + } + + const nextGroup = this.#queue.shift(); + if (nextGroup == null) { + state.busy = false; + state.assignment = null; + state.child.send({ type: 'shutdown' }); + return; + } + + state.busy = true; + state.assignment = nextGroup; + state.child.send({ + type: 'run', + testClass: nextGroup.testClass, + testPaths: nextGroup.testPaths, + }); + } + + #handleWorkerMessage(workerId, message) { + switch (message.type) { + case 'suite': + this.#handlers.startSuite?.(message.name, message.testClass); + break; + case 'pass': + this.#numPass += 1; + this.#handlers.pass?.(message.message, message.testClass); + break; + case 'fail': + this.#numFail += 1; + this.#handlers.fail?.(message.message, message.stack, message.testClass); + break; + case 'stack': + this.#handlers.reportStack?.(message.stack, message.testClass); + break; + case 'done': { + const state = this.#workerState.get(workerId); + if (state != null) { + state.busy = false; + state.assignment = null; + } + this.#dispatchNext(workerId); + break; + } + default: + break; + } + } + + #maybeFinishRun() { + const hasBusyWorkers = [...this.#workerState.values()].some(state => state.busy); + + if ( + this.#activeWorkers === 0 && + this.#queue.length === 0 && + !hasBusyWorkers && + this.#resolveRun != null + ) { + const resolve = this.#resolveRun; + this.#resolveRun = null; + this.#rejectRun = null; + resolve({ numPass: this.#numPass, numFail: this.#numFail }); + } + } +} + +/** + * Sequential fallback — same behavior as the original harness (single process). + */ +export async function runSequentialWpt({ filter, reporter }) { + const { setup } = createWptEnvironment(); + const failures = await wptRunner(testsPath, { rootURL, setup, filter, reporter }); + return failures; +} + +export function createParallelConsoleReporter() { + return { + startSuite: (name, testClass) => { + const label = testClass != null ? chalk.dim(`[${testClass}] `) : ''; + console.log(`\n${label}${chalk.bold.underline(path.join(testsPath, name))}\n`); + }, + pass: (message, testClass) => { + const label = testClass != null ? chalk.dim(`[${testClass}] `) : ''; + console.log(`${label}${chalk.green(` √ ${message}`)}`); + }, + fail: (message, stack, testClass) => { + const label = testClass != null ? chalk.dim(`[${testClass}] `) : ''; + console.log(`${label}${chalk.red(` × ${message}`)}`); + if (stack) { + console.log(chalk.dim(` ${stack}`)); + } + }, + reportStack: (stack, testClass) => { + const label = testClass != null ? chalk.dim(`[${testClass}] `) : ''; + console.log(`${label}${chalk.dim(` ${stack}`)}`); + }, + }; +} diff --git a/packages/react-native-audio-api/wpt_tests/wpt/mocks/XMLHttpRequest.js b/packages/react-native-audio-api/wpt_tests/wpt/mocks/XMLHttpRequest.js new file mode 100644 index 000000000..acd2fec9d --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/wpt/mocks/XMLHttpRequest.js @@ -0,0 +1,60 @@ +'use strict'; + +const fs = require('node:fs'); +const path = require('node:path'); + +function createXMLHttpRequest(testsPath) { + return class XMLHttpRequest { + constructor() { + this.readyState = 0; + this.status = 0; + this.response = null; + this.responseText = ''; + this.responseType = ''; + this.onreadystatechange = null; + this.onload = null; + this.onerror = null; + this._url = ''; + } + + open(method, url) { + this._method = method; + this._url = String(url); + this.readyState = 1; + this.#emitReadyStateChange(); + } + + send() { + try { + const normalized = this._url.replace(/^https?:\/\/[^/]+\//, ''); + const filePath = path.join(testsPath, '..', normalized); + const body = fs.readFileSync(filePath); + this.status = 200; + this.readyState = 4; + if (this.responseType === 'arraybuffer') { + this.response = body.buffer.slice(body.byteOffset, body.byteOffset + body.byteLength); + } else { + this.responseText = body.toString('utf8'); + this.response = this.responseText; + } + this.#emitReadyStateChange(); + if (typeof this.onload === 'function') { + this.onload(); + } + } catch (error) { + this.status = 404; + if (typeof this.onerror === 'function') { + this.onerror(error); + } + } + } + + #emitReadyStateChange() { + if (typeof this.onreadystatechange === 'function') { + this.onreadystatechange(); + } + } + }; +} + +module.exports = createXMLHttpRequest; diff --git a/packages/react-native-audio-api/wpt_tests/wpt/mocks/fetch.js b/packages/react-native-audio-api/wpt_tests/wpt/mocks/fetch.js new file mode 100644 index 000000000..e08a6f5ed --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/wpt/mocks/fetch.js @@ -0,0 +1,24 @@ +'use strict'; + +const fs = require('node:fs/promises'); +const path = require('node:path'); + +function createFetch(wptRootPath) { + return async function fetch(input) { + const url = String(input); + const normalized = url.replace(/^https?:\/\/[^/]+\//, ''); + const filePath = path.join(wptRootPath, normalized); + const body = await fs.readFile(filePath); + + return { + ok: true, + status: 200, + text: async () => body.toString('utf8'), + arrayBuffer: async () => + body.buffer.slice(body.byteOffset, body.byteOffset + body.byteLength), + json: async () => JSON.parse(body.toString('utf8')), + }; + }; +} + +module.exports = createFetch; diff --git a/packages/react-native-audio-api/wpt_tests/wpt/mocks/requestAnimationFrame.js b/packages/react-native-audio-api/wpt_tests/wpt/mocks/requestAnimationFrame.js new file mode 100644 index 000000000..241c509f6 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/wpt/mocks/requestAnimationFrame.js @@ -0,0 +1,44 @@ +'use strict'; + +const FRAME_INTERVAL_MS = 16; + +function createRequestAnimationFrame(window) { + let nextId = 0; + const handles = new Map(); + + function now() { + if (window.performance != null && typeof window.performance.now === 'function') { + return window.performance.now(); + } + return Date.now(); + } + + function requestAnimationFrame(callback) { + const id = ++nextId; + const timeoutId = setTimeout(() => { + handles.delete(id); + callback(now()); + }, FRAME_INTERVAL_MS); + handles.set(id, timeoutId); + return id; + } + + function cancelAnimationFrame(id) { + const timeoutId = handles.get(id); + if (timeoutId != null) { + clearTimeout(timeoutId); + handles.delete(id); + } + } + + function cancelAll() { + for (const timeoutId of handles.values()) { + clearTimeout(timeoutId); + } + handles.clear(); + } + + return { requestAnimationFrame, cancelAnimationFrame, cancelAll }; +} + +module.exports = createRequestAnimationFrame; diff --git a/packages/react-native-audio-api/wpt_tests/wpt/skip-list.json b/packages/react-native-audio-api/wpt_tests/wpt/skip-list.json new file mode 100644 index 000000000..89385a225 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/wpt/skip-list.json @@ -0,0 +1,50 @@ +[ + { + "pattern": "/crashtests/", + "reason": "excluded in smoke profile" + }, + { + "pattern": "/resources/", + "reason": "support files, not executable tests" + }, + { + "pattern": "the-audioworklet-interface", + "reason": "AudioWorklet is not available in the Node WPT build (RN_AUDIO_API_ENABLE_WORKLETS=0)" + }, + { + "pattern": "media-playback-while-not-visible-permission-policy", + "reason": "requires browser visibility/permission-policy infrastructure" + }, + { + "pattern": "audionode-channel-rules.html", + "reason": "hangs native offline renderer on large discrete-mixing graphs (engine bug, tracked separately)" + }, + { + "pattern": "-crash.html", + "reason": "browser crashtests without testharness stall the Node runner" + }, + { + "pattern": "historical.html", + "reason": "IDL harness page, not an executable smoke test" + }, + { + "pattern": "idlharness", + "reason": "IDL harness page, not an executable smoke test" + }, + { + "pattern": "audiocontext-not-fully-active", + "reason": "requires WPT /common/get-host-info.sub.js and cross-origin iframe infrastructure not available in Node harness" + }, + { + "pattern": "cors-check.https.html", + "reason": "requires WPT /common/get-host-info.sub.js and cross-origin infrastructure not available in Node harness" + }, + { + "pattern": "no-cors.https.html", + "reason": "requires WPT /common/get-host-info.sub.js and cross-origin infrastructure not available in Node harness" + }, + { + "pattern": "suspend-with-navigation", + "reason": "requires WPT /common/utils.js and dispatcher infrastructure not available in Node harness" + } +] diff --git a/packages/react-native-audio-api/wpt_tests/wpt/smoke-allowlist.json b/packages/react-native-audio-api/wpt_tests/wpt/smoke-allowlist.json new file mode 100644 index 000000000..ce62b3592 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/wpt/smoke-allowlist.json @@ -0,0 +1,3 @@ +[ + "the-audio-api" +] diff --git a/packages/react-native-audio-api/wpt_tests/wpt/wpt-harness.mjs b/packages/react-native-audio-api/wpt_tests/wpt/wpt-harness.mjs new file mode 100644 index 000000000..db10799ed --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/wpt/wpt-harness.mjs @@ -0,0 +1,144 @@ +import chalk from 'chalk'; +import { program } from 'commander'; + +import { + collectSelectedTestPaths, + createConsoleReporter, + createSequentialFilter, + createWptEnvironment, + printSummary, + resolveJobsOption, +} from './wpt-shared.mjs'; +import { + createParallelConsoleReporter, + runSequentialWpt, + WptParallelRunner, +} from './WptParallelRunner.mjs'; + +program + .option('--list', 'List test files only') + .option('--filter ', 'Additional regex filter for tests', '.*') + .option('--include-crashtests', 'Include crashtests', false) + .option( + '--jobs ', + 'Run test classes in parallel worker processes (1 = sequential)', + '1' + ); + +program.parse(process.argv); +const options = program.opts(); + +let numPass = 0; +let numFail = 0; +let timerStarted = false; +let summaryPrinted = false; +/** @type {import('./WptParallelRunner.mjs').WptParallelRunner | null} */ +let parallelRunner = null; + +const printHarnessSummary = () => { + if (summaryPrinted) { + return; + } + summaryPrinted = true; + + if (parallelRunner != null) { + parallelRunner.printSummary(); + return; + } + + printSummary({ numPass, numFail, timerStarted }); +}; + +const signalExitCode = { + SIGHUP: 129, + SIGINT: 130, + SIGTERM: 143, +}; + +const handleSignal = signal => { + console.error(chalk.yellow(`\nReceived ${signal}; printing partial summary.`)); + printHarnessSummary(); + + const failCount = + parallelRunner != null ? parallelRunner.getCounts().numFail : numFail; + const exitCode = signalExitCode[signal] ?? 1; + process.exit(failCount > 0 ? 1 : exitCode); +}; + +process.on('SIGHUP', () => handleSignal('SIGHUP')); +process.on('SIGINT', () => handleSignal('SIGINT')); +process.on('SIGTERM', () => handleSignal('SIGTERM')); + +process.on('unhandledRejection', error => { + const message = error instanceof Error ? error.stack || error.message : String(error); + console.error(chalk.red(`Unhandled rejection during WPT run:\n${message}`)); +}); + +process.on('uncaughtException', error => { + const message = error instanceof Error ? error.stack || error.message : String(error); + console.error(chalk.red(`Uncaught exception during WPT run:\n${message}`)); +}); + +if (options.list) { + for (const file of collectSelectedTestPaths({ + filterRegexp: options.filter, + includeCrashtests: options.includeCrashtests, + })) { + console.log(file); + } + process.exit(0); +} + +const jobs = resolveJobsOption(options.jobs); +const selectedTestPaths = collectSelectedTestPaths({ + filterRegexp: options.filter, + includeCrashtests: options.includeCrashtests, +}); + +// Warm up native module in the parent for sequential mode; workers load their own copy. +if (jobs === 1) { + createWptEnvironment(); +} + +try { + console.time('wpt-duration'); + timerStarted = true; + + if (jobs === 1) { + const numPassRef = { value: 0 }; + const numFailRef = { value: 0 }; + const filter = createSequentialFilter({ + filterRegexp: options.filter, + includeCrashtests: options.includeCrashtests, + listOnly: false, + }); + const reporter = createConsoleReporter({ numPassRef, numFailRef }); + const fileFailures = await runSequentialWpt({ filter, reporter }); + numPass = numPassRef.value; + numFail = numFailRef.value; + if (fileFailures > 0 && numFail === 0) { + numFail = fileFailures; + } + } else { + parallelRunner = new WptParallelRunner({ + jobs, + handlers: createParallelConsoleReporter(), + }); + parallelRunner.markTimerStarted(); + const result = await parallelRunner.run(selectedTestPaths); + numPass = result.numPass; + numFail = result.numFail; + parallelRunner.printSummary(); + summaryPrinted = true; + parallelRunner = null; + } + + if (!summaryPrinted) { + printHarnessSummary(); + } + process.exit(numFail > 0 ? 1 : 0); +} catch (error) { + printHarnessSummary(); + console.error(error.stack); + process.exit(1); +} diff --git a/packages/react-native-audio-api/wpt_tests/wpt/wpt-shared.mjs b/packages/react-native-audio-api/wpt_tests/wpt/wpt-shared.mjs new file mode 100644 index 000000000..d69bb58b1 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/wpt/wpt-shared.mjs @@ -0,0 +1,236 @@ +import EventEmitter from 'node:events'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { createRequire } from 'node:module'; + +import chalk from 'chalk'; + +import { wrapAudioNodeConstructors } from './wrap-audio-node-constructors.mjs'; + +const require = createRequire(import.meta.url); +const { setFloat32ArrayViewFactory } = require('../../lib/commonjs/errors/index.js'); +const createRequestAnimationFrame = require('./mocks/requestAnimationFrame.js'); + +export const harnessDir = path.dirname(new URL(import.meta.url).pathname); +export const testsPath = path.join(harnessDir, '..', 'webaudio'); +export const rootURL = 'webaudio'; + +export const smokeAllowlist = JSON.parse( + fs.readFileSync(path.join(harnessDir, 'smoke-allowlist.json'), 'utf8') +); +export const skipList = JSON.parse( + fs.readFileSync(path.join(harnessDir, 'skip-list.json'), 'utf8') +); + +export function resolveJobsOption(jobsOption) { + if (jobsOption == null || jobsOption === '1') { + return 1; + } + if (jobsOption === 'auto') { + return Math.max(1, (os.cpus()?.length ?? 1) - 1); + } + const parsed = Number.parseInt(String(jobsOption), 10); + if (!Number.isFinite(parsed) || parsed < 1) { + throw new Error(`Invalid --jobs value: ${jobsOption}`); + } + return parsed; +} + +export function walkHtmlFiles(rootDir, prefix = '') { + const entries = fs.readdirSync(path.join(rootDir, prefix), { withFileTypes: true }); + let files = []; + for (const entry of entries) { + const rel = path.join(prefix, entry.name); + if (entry.isDirectory()) { + files = files.concat(walkHtmlFiles(rootDir, rel)); + } else if (entry.name.endsWith('.html')) { + files.push(rel); + } + } + return files; +} + +export function smokeFilter(name) { + return smokeAllowlist.some(prefix => name.includes(prefix)); +} + +export function getSkippedByPolicy(name) { + return skipList.find(item => name.includes(item.pattern)); +} + +export function normalizeTestPath(filePath) { + return filePath.split(path.sep).join('/'); +} + +/** + * WPT "test class" — typically one interface directory under the-audio-api/. + * Used to batch independent tests into worker processes. + */ +export function getTestClass(testPath) { + const normalized = normalizeTestPath(testPath); + const parts = normalized.split('/'); + + if (parts[0] === 'the-audio-api' && parts.length >= 3) { + return `${parts[0]}/${parts[1]}`; + } + + if (parts.length >= 2) { + return parts.slice(0, -1).join('/'); + } + + return 'root'; +} + +export function groupTestsByClass(testPaths) { + const groups = new Map(); + + for (const testPath of testPaths) { + const testClass = getTestClass(testPath); + const bucket = groups.get(testClass) ?? []; + bucket.push(testPath); + groups.set(testClass, bucket); + } + + return [...groups.entries()] + .sort(([a], [b]) => a.localeCompare(b)) + .map(([testClass, paths]) => ({ + testClass, + testPaths: paths.sort(), + })); +} + +export function collectSelectedTestPaths({ + filterRegexp = '.*', + includeCrashtests = false, +}) { + const extraFilterRe = new RegExp(filterRegexp); + const selected = []; + + for (const file of walkHtmlFiles(testsPath)) { + const fullName = normalizeTestPath(file); + if (getSkippedByPolicy(fullName) != null) { + continue; + } + if (!includeCrashtests && fullName.includes('/crashtests/')) { + continue; + } + if (!smokeFilter(fullName)) { + continue; + } + if (!extraFilterRe.test(fullName)) { + continue; + } + selected.push(fullName); + } + + return selected.sort(); +} + +export function loadNodeAudioApi() { + const nodeAudioApi = require('../index.js'); + const { TypeError: _TypeError, RangeError: _RangeError, ...audioApiForWindow } = + nodeAudioApi; + return { nodeAudioApi, audioApiForWindow }; +} + +export function createWptEnvironment() { + const cleanupEmitter = new EventEmitter(); + const { nodeAudioApi, audioApiForWindow } = loadNodeAudioApi(); + let cancelPendingAnimationFrames = () => {}; + + cleanupEmitter.on('cleanup', () => { + cancelPendingAnimationFrames(); + }); + + const setup = window => { + cleanupEmitter.emit('cleanup'); + + setFloat32ArrayViewFactory( + (buffer, byteOffset, length) => + new window.Float32Array(buffer, byteOffset, length) + ); + + Object.assign(window, audioApiForWindow); + // Library throws via globalThis.TypeError/RangeError; align with the test + // page realm so audit.js constructor checks (error.constructor === TypeError) + // pass under jsdom. + globalThis.TypeError = window.TypeError; + globalThis.RangeError = window.RangeError; + wrapAudioNodeConstructors(window); + if (window.navigator == null) { + window.navigator = {}; + } + window.navigator.mediaDevices = nodeAudioApi.mediaDevices; + + const animationFrame = createRequestAnimationFrame(window); + window.requestAnimationFrame = animationFrame.requestAnimationFrame; + window.cancelAnimationFrame = animationFrame.cancelAnimationFrame; + cancelPendingAnimationFrames = animationFrame.cancelAll; + }; + + return { setup, cleanupEmitter }; +} + +export function createSequentialFilter({ filterRegexp, includeCrashtests, listOnly }) { + const extraFilterRe = new RegExp(filterRegexp); + + return name => { + if (getSkippedByPolicy(name) != null) { + return false; + } + if (!includeCrashtests && name.includes('/crashtests/')) { + return false; + } + if (!smokeFilter(name)) { + return false; + } + if (!extraFilterRe.test(name)) { + return false; + } + if (listOnly) { + console.log(name); + return false; + } + return true; + }; +} + +export function createReporter(handlers) { + return { + startSuite: name => handlers.startSuite?.(name), + pass: message => handlers.pass?.(message), + fail: message => handlers.fail?.(message), + reportStack: stack => handlers.reportStack?.(stack), + }; +} + +export function createConsoleReporter({ numPassRef, numFailRef }) { + return createReporter({ + startSuite: name => { + console.log(`\n${chalk.bold.underline(path.join(testsPath, name))}\n`); + }, + pass: message => { + numPassRef.value += 1; + console.log(chalk.green(` √ ${message}`)); + }, + fail: message => { + numFailRef.value += 1; + console.log(chalk.red(` × ${message}`)); + }, + reportStack: stack => { + console.log(chalk.dim(` ${stack}`)); + }, + }); +} + +export function printSummary({ numPass, numFail, timerStarted }) { + const total = numPass + numFail; + const passRate = total > 0 ? ((numPass / total) * 100).toFixed(1) : '0.0'; + console.log(chalk.bold(`\nPASS: ${numPass}`)); + console.log(chalk.bold(`FAIL: ${numFail}`)); + console.log(chalk.bold(`PASS RATE: ${passRate}% (${numPass}/${total})`)); + if (timerStarted) { + console.timeEnd('wpt-duration'); + } +} diff --git a/packages/react-native-audio-api/wpt_tests/wpt/wpt-worker.mjs b/packages/react-native-audio-api/wpt_tests/wpt/wpt-worker.mjs new file mode 100644 index 000000000..9a2775f71 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/wpt/wpt-worker.mjs @@ -0,0 +1,87 @@ +import wptRunner from 'wpt-runner'; + +import { + createReporter, + createWptEnvironment, + normalizeTestPath, + rootURL, + testsPath, +} from './wpt-shared.mjs'; + +const workerId = process.env.WPT_WORKER_ID ?? '0'; +const { setup } = createWptEnvironment(); + +function safeSend(message) { + if (!process.connected) { + return false; + } + + try { + process.send(message); + return true; + } catch { + return false; + } +} + +process.on('message', async message => { + if (message?.type === 'shutdown') { + process.exit(0); + return; + } + + if (message?.type !== 'run') { + return; + } + + const allowedPaths = new Set(message.testPaths.map(normalizeTestPath)); + const testClass = message.testClass; + + let numPass = 0; + let numFail = 0; + + const reporter = createReporter({ + startSuite: name => { + safeSend({ type: 'suite', name, testClass }); + }, + pass: msg => { + numPass += 1; + safeSend({ type: 'pass', message: msg, testClass }); + }, + fail: msg => { + numFail += 1; + safeSend({ type: 'fail', message: msg, testClass }); + }, + reportStack: stack => { + safeSend({ type: 'stack', stack, testClass }); + }, + }); + + const filter = (name, _url) => allowedPaths.has(normalizeTestPath(name)); + + try { + await wptRunner(testsPath, { rootURL, setup, filter, reporter }); + safeSend({ + type: 'done', + testClass, + numPass, + numFail, + workerId, + }); + } catch (error) { + const stack = error instanceof Error ? error.stack || error.message : String(error); + safeSend({ + type: 'fail', + message: `Worker ${workerId} failed while running ${testClass}`, + stack, + testClass, + }); + safeSend({ + type: 'done', + testClass, + numPass, + numFail: numFail + 1, + workerId, + }); + } +}); diff --git a/packages/react-native-audio-api/wpt_tests/wpt/wrap-audio-node-constructors.mjs b/packages/react-native-audio-api/wpt_tests/wpt/wrap-audio-node-constructors.mjs new file mode 100644 index 000000000..a3d48ebe2 --- /dev/null +++ b/packages/react-native-audio-api/wpt_tests/wpt/wrap-audio-node-constructors.mjs @@ -0,0 +1,133 @@ +/** + * Wrap Web Audio node constructors so invalid-argument TypeErrors are thrown + * from the jsdom window realm. Node-loaded modules otherwise throw Node's + * TypeError (e.g. on `undefined.context`), which audit.js rejects. + */ + +const AUDIO_NODE_CONSTRUCTORS = [ + { name: 'AnalyserNode' }, + { name: 'AudioBufferSourceNode' }, + { name: 'BiquadFilterNode' }, + { name: 'ConstantSourceNode' }, + { name: 'ConvolverNode' }, + { name: 'DelayNode' }, + { name: 'GainNode' }, + { name: 'IIRFilterNode', optionsRequired: true }, + { name: 'OscillatorNode' }, + { name: 'StereoPannerNode' }, + { name: 'WaveShaperNode' }, +]; + +function isBaseAudioContext(value) { + return ( + value != null && + typeof value === 'object' && + 'context' in value && + 'destination' in value && + 'sampleRate' in value + ); +} + +function isOptionsDictionary(value) { + if (value === undefined || value === null) { + return true; + } + + return typeof value === 'object' && !Array.isArray(value); +} + +function wrapAudioNodeConstructor(Original, window, optionsRequired = false) { + function Wrapped(...args) { + const [context, options] = args; + + if (!isBaseAudioContext(context)) { + throw new window.TypeError(); + } + + if (optionsRequired && (options === undefined || options === null)) { + throw new window.TypeError(); + } + + if (!isOptionsDictionary(options)) { + throw new window.TypeError(); + } + + return Reflect.construct(Original, args, new.target ?? Wrapped); + } + + Wrapped.prototype = Original.prototype; + Object.defineProperty(Wrapped, 'name', { value: Original.name }); + + return Wrapped; +} + +export function wrapAudioNodeConstructors(window) { + for (const { name, optionsRequired = false } of AUDIO_NODE_CONSTRUCTORS) { + const Original = window[name]; + if (typeof Original !== 'function') { + continue; + } + + window[name] = wrapAudioNodeConstructor(Original, window, optionsRequired); + } + + wrapAudioNodeConnectDisconnect(window); +} + +const DOM_EXCEPTION_NAMES = new Set([ + 'IndexSizeError', + 'InvalidAccessError', + 'InvalidStateError', + 'NotSupportedError', + 'SyntaxError', + 'TypeError', + 'SecurityError', + 'NetworkError', + 'AbortError', + 'DataError', + 'EncodingError', + 'NotReadableError', + 'UnknownError', + 'ConstraintError', + 'QuotaExceededError', + 'TimeoutError', +]); + +function toWindowDomException(window, error) { + if (error instanceof window.DOMException) { + return error; + } + + const name = error?.name; + if (typeof name === 'string' && DOM_EXCEPTION_NAMES.has(name) && window.DOMException != null) { + return new window.DOMException(error.message, name); + } + + return error; +} + +function wrapAudioNodeConnectDisconnect(window) { + const AudioNode = window.AudioNode; + if (typeof AudioNode !== 'function') { + return; + } + + const originalConnect = AudioNode.prototype.connect; + const originalDisconnect = AudioNode.prototype.disconnect; + + AudioNode.prototype.connect = function connect(...args) { + try { + return originalConnect.apply(this, args); + } catch (error) { + throw toWindowDomException(window, error); + } + }; + + AudioNode.prototype.disconnect = function disconnect(...args) { + try { + return originalDisconnect.apply(this, args); + } catch (error) { + throw toWindowDomException(window, error); + } + }; +} diff --git a/yarn.lock b/yarn.lock index e330f7f2e..ace699dcd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,6 +5,46 @@ __metadata: version: 8 cacheKey: 10 +"@asamuzakjp/css-color@npm:^5.1.11": + version: 5.1.11 + resolution: "@asamuzakjp/css-color@npm:5.1.11" + dependencies: + "@asamuzakjp/generational-cache": "npm:^1.0.1" + "@csstools/css-calc": "npm:^3.2.0" + "@csstools/css-color-parser": "npm:^4.1.0" + "@csstools/css-parser-algorithms": "npm:^4.0.0" + "@csstools/css-tokenizer": "npm:^4.0.0" + checksum: 10/2e337cc94b5a3f9741a27f92b4e4b7dc467a76b1dcf66c40e71808fed71695f10c8cf07c8b13313cbb637154314ca1d8626bb9a045fe94b404b242a390cf3bd3 + languageName: node + linkType: hard + +"@asamuzakjp/dom-selector@npm:^7.1.1": + version: 7.1.1 + resolution: "@asamuzakjp/dom-selector@npm:7.1.1" + dependencies: + "@asamuzakjp/generational-cache": "npm:^1.0.1" + "@asamuzakjp/nwsapi": "npm:^2.3.9" + bidi-js: "npm:^1.0.3" + css-tree: "npm:^3.2.1" + is-potential-custom-element-name: "npm:^1.0.1" + checksum: 10/49a065a64db5f53a3008c231d09606e4b67f509fa20148a67419451c2dc91a421202ed17bfc4bc679ad2f0432d7260720d602c1d5c9c5e165931fff5199c3f12 + languageName: node + linkType: hard + +"@asamuzakjp/generational-cache@npm:^1.0.1": + version: 1.0.1 + resolution: "@asamuzakjp/generational-cache@npm:1.0.1" + checksum: 10/e1cf3f1916a334c6153f624982f0eb3d50fa3048435ea5c5b0f441f8f1ab74a0fe992dac214b612d22c0acafad3cd1a1f6b45d99c7b6e3b63cfdf7f6ca5fc144 + languageName: node + linkType: hard + +"@asamuzakjp/nwsapi@npm:^2.3.9": + version: 2.3.9 + resolution: "@asamuzakjp/nwsapi@npm:2.3.9" + checksum: 10/95a6d1c102e1117fe818da087fcc5b914d23e0699855991bae50b891435dd1945ad7d384198f8bcf616207fd85b7ec32e3db6b96e9309d84c6903b8dc4151e34 + languageName: node + linkType: hard + "@babel/cli@npm:^7.20.0": version: 7.28.6 resolution: "@babel/cli@npm:7.28.6" @@ -1568,6 +1608,17 @@ __metadata: languageName: node linkType: hard +"@bramus/specificity@npm:^2.4.2": + version: 2.4.2 + resolution: "@bramus/specificity@npm:2.4.2" + dependencies: + css-tree: "npm:^3.0.0" + bin: + specificity: bin/cli.js + checksum: 10/4255ed6ff12f7db9ec3c21acfd0da2327d30ec29deb199345810cdcad992618f40039c5483eefeb665913bffbc80b690e9f1b954fbbbfa93480c6a22f9c3a69c + languageName: node + linkType: hard + "@commitlint/cli@npm:^17.0.2": version: 17.8.1 resolution: "@commitlint/cli@npm:17.8.1" @@ -1774,6 +1825,64 @@ __metadata: languageName: node linkType: hard +"@csstools/color-helpers@npm:^6.1.0": + version: 6.1.0 + resolution: "@csstools/color-helpers@npm:6.1.0" + checksum: 10/acb6a7e0f2dad6cd5527b455732d6ceab836de8469e7f31be0f60748a1609794fd0a478e116931fddee63577562a40d9ef122a58c4f19de229ae233d1307c373 + languageName: node + linkType: hard + +"@csstools/css-calc@npm:^3.2.0, @csstools/css-calc@npm:^3.2.1": + version: 3.2.1 + resolution: "@csstools/css-calc@npm:3.2.1" + peerDependencies: + "@csstools/css-parser-algorithms": ^4.0.0 + "@csstools/css-tokenizer": ^4.0.0 + checksum: 10/39042a9382cbd7c4fa241c1a6c10d64c23fa7653970fc11df532e9bc42a366a8b50c3ac3036bd5f2a77b94144e7f804f19d2b52800ad2f48bd9a3840377165d8 + languageName: node + linkType: hard + +"@csstools/css-color-parser@npm:^4.1.0": + version: 4.1.9 + resolution: "@csstools/css-color-parser@npm:4.1.9" + dependencies: + "@csstools/color-helpers": "npm:^6.1.0" + "@csstools/css-calc": "npm:^3.2.1" + peerDependencies: + "@csstools/css-parser-algorithms": ^4.0.0 + "@csstools/css-tokenizer": ^4.0.0 + checksum: 10/6369b601bcd3a8ce58dbcdc389a732b754c8f3fc35421b37169f6d4b07c7261f7b8c23e7d04e457da5e5e0bb082e680acb137d8c86fa1f7d6ff14ea873bf02a2 + languageName: node + linkType: hard + +"@csstools/css-parser-algorithms@npm:^4.0.0": + version: 4.0.0 + resolution: "@csstools/css-parser-algorithms@npm:4.0.0" + peerDependencies: + "@csstools/css-tokenizer": ^4.0.0 + checksum: 10/000f3ba55f440d9fbece50714e88f9d4479e2bde9e0568333492663f2c6034dc31d0b9ef5d66d196c76be58eea145ca6920aa8bdfdcc6361894806c21b5402d0 + languageName: node + linkType: hard + +"@csstools/css-syntax-patches-for-csstree@npm:^1.1.3": + version: 1.1.6 + resolution: "@csstools/css-syntax-patches-for-csstree@npm:1.1.6" + peerDependencies: + css-tree: ^3.2.1 + peerDependenciesMeta: + css-tree: + optional: true + checksum: 10/8747268b42f1afbe450d38b7f388a4983c810883f8c0716fa24f5b1eef0f9cbaa3a0f4ea72d1e5cbd015dc4fd5af9cc96ade42792912ed2dcc1d4054de102163 + languageName: node + linkType: hard + +"@csstools/css-tokenizer@npm:^4.0.0": + version: 4.0.0 + resolution: "@csstools/css-tokenizer@npm:4.0.0" + checksum: 10/074ade1a7fc3410b813c8982cf07a56814a55af509c533c2dc80d5689f34d2ba38219f8fa78fa36ea2adc6c5db506ea3c3a667388dda1b59b1281fdd2a2d1e28 + languageName: node + linkType: hard + "@egjs/hammerjs@npm:^2.0.17": version: 2.0.17 resolution: "@egjs/hammerjs@npm:2.0.17" @@ -1848,6 +1957,18 @@ __metadata: languageName: node linkType: hard +"@exodus/bytes@npm:^1.11.0, @exodus/bytes@npm:^1.15.0, @exodus/bytes@npm:^1.6.0": + version: 1.15.1 + resolution: "@exodus/bytes@npm:1.15.1" + peerDependencies: + "@noble/hashes": ^1.8.0 || ^2.0.0 + peerDependenciesMeta: + "@noble/hashes": + optional: true + checksum: 10/7dde00ae8040ec032ba3c287d210d7d555986caaf81a1215311c180422697d739a1952eb9d91e841132b18a19a910cdd02e4914136db3cc87baaa0fdd84b1e87 + languageName: node + linkType: hard + "@expo/config-plugins@npm:^9.0.0": version: 9.1.7 resolution: "@expo/config-plugins@npm:9.1.7" @@ -3260,6 +3381,15 @@ __metadata: languageName: node linkType: hard +"@types/readable-stream@npm:^4.0.0": + version: 4.0.24 + resolution: "@types/readable-stream@npm:4.0.24" + dependencies: + "@types/node": "npm:*" + checksum: 10/e96af36f032495f28fac2df2a13d92ced3c7f76cd51d418fb60f960f997f79c6116ad40831539d76260b2e831a914f758f68d810bd52aeb2dc8b8a603238a0fb + languageName: node + linkType: hard + "@types/semver@npm:7.7.1, @types/semver@npm:^7.3.12": version: 7.7.1 resolution: "@types/semver@npm:7.7.1" @@ -3598,6 +3728,15 @@ __metadata: languageName: node linkType: hard +"agent-base@npm:6": + version: 6.0.2 + resolution: "agent-base@npm:6.0.2" + dependencies: + debug: "npm:4" + checksum: 10/21fb903e0917e5cb16591b4d0ef6a028a54b83ac30cd1fca58dece3d4e0990512a8723f9f83130d88a41e2af8b1f7be1386fda3ea2d181bb1a62155e75e95e23 + languageName: node + linkType: hard + "agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": version: 7.1.4 resolution: "agent-base@npm:7.1.4" @@ -3734,7 +3873,7 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^6.1.0": +"ansi-styles@npm:^6.1.0, ansi-styles@npm:^6.2.1": version: 6.2.3 resolution: "ansi-styles@npm:6.2.3" checksum: 10/c49dad7639f3e48859bd51824c93b9eb0db628afc243c51c3dd2410c4a15ede1a83881c6c7341aa2b159c4f90c11befb38f2ba848c07c66c9f9de4bcd7cb9f30 @@ -3758,6 +3897,13 @@ __metadata: languageName: node linkType: hard +"aproba@npm:^1.0.3 || ^2.0.0": + version: 2.1.0 + resolution: "aproba@npm:2.1.0" + checksum: 10/cb0e335ac398027d43bf4a139337363e161fa10a642291f7ad5068a2e24797be58270775047cba901a7c1ce945a05c7535b13f6457993517cd7dca40c9b00a00 + languageName: node + linkType: hard + "are-docs-informative@npm:^0.0.2": version: 0.0.2 resolution: "are-docs-informative@npm:0.0.2" @@ -3765,6 +3911,16 @@ __metadata: languageName: node linkType: hard +"are-we-there-yet@npm:^3.0.0": + version: 3.0.1 + resolution: "are-we-there-yet@npm:3.0.1" + dependencies: + delegates: "npm:^1.0.0" + readable-stream: "npm:^3.6.0" + checksum: 10/390731720e1bf9ed5d0efc635ea7df8cbc4c90308b0645a932f06e8495a0bf1ecc7987d3b97e805f62a17d6c4b634074b25200aa4d149be2a7b17250b9744bc4 + languageName: node + linkType: hard + "arg@npm:^4.1.0": version: 4.1.3 resolution: "arg@npm:4.1.3" @@ -3951,6 +4107,13 @@ __metadata: languageName: node linkType: hard +"asynckit@npm:^0.4.0": + version: 0.4.0 + resolution: "asynckit@npm:0.4.0" + checksum: 10/3ce727cbc78f69d6a4722517a58ee926c8c21083633b1d3fdf66fd688f6c127a53a592141bd4866f9b63240a86e9d8e974b13919450bd17fa33c2d22c4558ad8 + languageName: node + linkType: hard + "available-typed-arrays@npm:^1.0.7": version: 1.0.7 resolution: "available-typed-arrays@npm:1.0.7" @@ -3960,6 +4123,18 @@ __metadata: languageName: node linkType: hard +"axios@npm:^1.6.5": + version: 1.18.1 + resolution: "axios@npm:1.18.1" + dependencies: + follow-redirects: "npm:^1.16.0" + form-data: "npm:^4.0.5" + https-proxy-agent: "npm:^5.0.1" + proxy-from-env: "npm:^2.1.0" + checksum: 10/c4cdced3ee0a9bf7dcae189fbc74a124aa079d4f04dbd995e602d39c1419476e8d021f87ee39ac8d8398e5a55e6d0b986238b3645f0d9177ac80de87c2a73f18 + languageName: node + linkType: hard + "babel-jest@npm:^29.7.0": version: 29.7.0 resolution: "babel-jest@npm:29.7.0" @@ -4161,6 +4336,15 @@ __metadata: languageName: node linkType: hard +"bidi-js@npm:^1.0.3": + version: 1.0.3 + resolution: "bidi-js@npm:1.0.3" + dependencies: + require-from-string: "npm:^2.0.2" + checksum: 10/c4341c7a98797efe3d186cd99d6f97e9030a4f959794ca200ef2ec0a678483a916335bba6c2c0608a21d04a221288a31c9fd0faa0cd9b3903b93594b42466a6a + languageName: node + linkType: hard + "big-integer@npm:1.6.x": version: 1.6.52 resolution: "big-integer@npm:1.6.52" @@ -4193,6 +4377,18 @@ __metadata: languageName: node linkType: hard +"bl@npm:^6.1.0": + version: 6.1.6 + resolution: "bl@npm:6.1.6" + dependencies: + "@types/readable-stream": "npm:^4.0.0" + buffer: "npm:^6.0.3" + inherits: "npm:^2.0.4" + readable-stream: "npm:^4.2.0" + checksum: 10/396f53ae7047046273e7b20f956e3368c1187bdc0520bd94c9a9db1fb337e469e1b30f09188d69507a344f27286e9ce3a57780f13204e031a15596b4bc5f0781 + languageName: node + linkType: hard + "body-parser@npm:^1.20.3": version: 1.20.4 resolution: "body-parser@npm:1.20.4" @@ -4316,6 +4512,16 @@ __metadata: languageName: node linkType: hard +"buffer@npm:^6.0.3": + version: 6.0.3 + resolution: "buffer@npm:6.0.3" + dependencies: + base64-js: "npm:^1.3.1" + ieee754: "npm:^1.2.1" + checksum: 10/b6bc68237ebf29bdacae48ce60e5e28fc53ae886301f2ad9496618efac49427ed79096750033e7eab1897a4f26ae374ace49106a5758f38fb70c78c9fda2c3b1 + languageName: node + linkType: hard + "builtin-modules@npm:^3.3.0": version: 3.3.0 resolution: "builtin-modules@npm:3.3.0" @@ -4495,6 +4701,13 @@ __metadata: languageName: node linkType: hard +"chalk@npm:^5.3.0": + version: 5.6.2 + resolution: "chalk@npm:5.6.2" + checksum: 10/1b2f48f6fba1370670d5610f9cd54c391d6ede28f4b7062dd38244ea5768777af72e5be6b74fb6c6d54cb84c4a2dff3f3afa9b7cb5948f7f022cfd3d087989e0 + languageName: node + linkType: hard + "char-regex@npm:^1.0.2": version: 1.0.2 resolution: "char-regex@npm:1.0.2" @@ -4528,6 +4741,13 @@ __metadata: languageName: node linkType: hard +"chownr@npm:^2.0.0": + version: 2.0.0 + resolution: "chownr@npm:2.0.0" + checksum: 10/c57cf9dd0791e2f18a5ee9c1a299ae6e801ff58fee96dc8bfd0dcb4738a6ce58dd252a3605b1c93c6418fe4f9d5093b28ffbf4d66648cb2a9c67eaef9679be2f + languageName: node + linkType: hard + "chownr@npm:^3.0.0": version: 3.0.0 resolution: "chownr@npm:3.0.0" @@ -4637,6 +4857,17 @@ __metadata: languageName: node linkType: hard +"cliui@npm:^9.0.1": + version: 9.0.1 + resolution: "cliui@npm:9.0.1" + dependencies: + string-width: "npm:^7.2.0" + strip-ansi: "npm:^7.1.0" + wrap-ansi: "npm:^9.0.0" + checksum: 10/df43d8d1c6e3254cbb64b1905310d5f6672c595496a3cbe76946c6d24777136886470686f2772ac9edfe547a74bb70e8017530b3554715aee119efd7752fc0d9 + languageName: node + linkType: hard + "clone@npm:^1.0.2": version: 1.0.4 resolution: "clone@npm:1.0.4" @@ -4644,6 +4875,28 @@ __metadata: languageName: node linkType: hard +"cmake-js@npm:^7.3.1": + version: 7.4.0 + resolution: "cmake-js@npm:7.4.0" + dependencies: + axios: "npm:^1.6.5" + debug: "npm:^4" + fs-extra: "npm:^11.2.0" + memory-stream: "npm:^1.0.0" + node-api-headers: "npm:^1.1.0" + npmlog: "npm:^6.0.2" + rc: "npm:^1.2.7" + semver: "npm:^7.5.4" + tar: "npm:^6.2.0" + url-join: "npm:^4.0.1" + which: "npm:^2.0.2" + yargs: "npm:^17.7.2" + bin: + cmake-js: bin/cmake-js + checksum: 10/c60d30c53c583b71b11882f13bf1570dd2bb946490cda5117ad33a9c5dfa9865f66ea856da5afb0c3088ae31d44e16d1cc49f6004f9469a52bbeb2d1b0d000cf + languageName: node + linkType: hard + "co@npm:^4.6.0": version: 4.6.0 resolution: "co@npm:4.6.0" @@ -4700,6 +4953,15 @@ __metadata: languageName: node linkType: hard +"color-support@npm:^1.1.3": + version: 1.1.3 + resolution: "color-support@npm:1.1.3" + bin: + color-support: bin.js + checksum: 10/4bcfe30eea1498fe1cabc852bbda6c9770f230ea0e4faf4611c5858b1b9e4dde3730ac485e65f54ca182f4c50b626c1bea7c8441ceda47367a54a818c248aa7a + languageName: node + linkType: hard + "color@npm:^4.2.3": version: 4.2.3 resolution: "color@npm:4.2.3" @@ -4717,6 +4979,15 @@ __metadata: languageName: node linkType: hard +"combined-stream@npm:^1.0.8": + version: 1.0.8 + resolution: "combined-stream@npm:1.0.8" + dependencies: + delayed-stream: "npm:~1.0.0" + checksum: 10/2e969e637d05d09fa50b02d74c83a1186f6914aae89e6653b62595cc75a221464f884f55f231b8f4df7a49537fba60bdc0427acd2bf324c09a1dbb84837e36e4 + languageName: node + linkType: hard + "command-exists@npm:^1.2.8": version: 1.2.9 resolution: "command-exists@npm:1.2.9" @@ -4731,6 +5002,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:^14.0.0": + version: 14.0.3 + resolution: "commander@npm:14.0.3" + checksum: 10/dfa9ebe2a433d277de5cb0252d23b10a543d245d892db858d23b516336a835c50fd4f52bee4cd13c705cc8acb6f03dc632c73dd806f7d06d3353eb09953dd17a + languageName: node + linkType: hard + "commander@npm:^2.20.0": version: 2.20.3 resolution: "commander@npm:2.20.3" @@ -4876,6 +5154,13 @@ __metadata: languageName: node linkType: hard +"console-control-strings@npm:^1.1.0": + version: 1.1.0 + resolution: "console-control-strings@npm:1.1.0" + checksum: 10/27b5fa302bc8e9ae9e98c03c66d76ca289ad0c61ce2fe20ab288d288bee875d217512d2edb2363fc83165e88f1c405180cf3f5413a46e51b4fe1a004840c6cdb + languageName: node + linkType: hard + "content-type@npm:~1.0.5": version: 1.0.5 resolution: "content-type@npm:1.0.5" @@ -5056,6 +5341,16 @@ __metadata: languageName: node linkType: hard +"css-tree@npm:^3.0.0, css-tree@npm:^3.2.1": + version: 3.2.1 + resolution: "css-tree@npm:3.2.1" + dependencies: + mdn-data: "npm:2.27.1" + source-map-js: "npm:^1.2.1" + checksum: 10/9945b387bdec756738c34d64b8287f05ca6645f51d1c8abaaa5822ec3e74533604103aaad164b8100afd8495e92120be7c1c6afbe5be89f867acc5b456ddd79c + languageName: node + linkType: hard + "css-what@npm:^6.1.0": version: 6.2.2 resolution: "css-what@npm:6.2.2" @@ -5077,6 +5372,16 @@ __metadata: languageName: node linkType: hard +"data-urls@npm:^7.0.0": + version: 7.0.0 + resolution: "data-urls@npm:7.0.0" + dependencies: + whatwg-mimetype: "npm:^5.0.0" + whatwg-url: "npm:^16.0.0" + checksum: 10/60f88ded4306aea5d6251c4db100ca272fc026014004d68aad4db495397a73bb39d17a6bd29ed9ab348c88a28f6e97266a1759985df4e12dc8c02bb8544c7731 + languageName: node + linkType: hard + "data-view-buffer@npm:^1.0.2": version: 1.0.2 resolution: "data-view-buffer@npm:1.0.2" @@ -5126,7 +5431,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.0.0, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.4.0, debug@npm:^4.4.1, debug@npm:^4.4.3": +"debug@npm:4, debug@npm:^4, debug@npm:^4.0.0, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.4.0, debug@npm:^4.4.1, debug@npm:^4.4.3": version: 4.4.3 resolution: "debug@npm:4.4.3" dependencies: @@ -5171,6 +5476,13 @@ __metadata: languageName: node linkType: hard +"decimal.js@npm:^10.6.0": + version: 10.6.0 + resolution: "decimal.js@npm:10.6.0" + checksum: 10/c0d45842d47c311d11b38ce7ccc911121953d4df3ebb1465d92b31970eb4f6738a065426a06094af59bee4b0d64e42e7c8984abd57b6767c64ea90cf90bb4a69 + languageName: node + linkType: hard + "decode-named-character-reference@npm:^1.0.0": version: 1.3.0 resolution: "decode-named-character-reference@npm:1.3.0" @@ -5206,6 +5518,13 @@ __metadata: languageName: node linkType: hard +"deep-extend@npm:^0.6.0": + version: 0.6.0 + resolution: "deep-extend@npm:0.6.0" + checksum: 10/7be7e5a8d468d6b10e6a67c3de828f55001b6eb515d014f7aeb9066ce36bd5717161eb47d6a0f7bed8a9083935b465bc163ee2581c8b128d29bf61092fdf57a7 + languageName: node + linkType: hard + "deep-is@npm:^0.1.3": version: 0.1.4 resolution: "deep-is@npm:0.1.4" @@ -5296,6 +5615,20 @@ __metadata: languageName: node linkType: hard +"delayed-stream@npm:~1.0.0": + version: 1.0.0 + resolution: "delayed-stream@npm:1.0.0" + checksum: 10/46fe6e83e2cb1d85ba50bd52803c68be9bd953282fa7096f51fc29edd5d67ff84ff753c51966061e5ba7cb5e47ef6d36a91924eddb7f3f3483b1c560f77a0020 + languageName: node + linkType: hard + +"delegates@npm:^1.0.0": + version: 1.0.0 + resolution: "delegates@npm:1.0.0" + checksum: 10/a51744d9b53c164ba9c0492471a1a2ffa0b6727451bdc89e31627fdf4adda9d51277cfcbfb20f0a6f08ccb3c436f341df3e92631a3440226d93a8971724771fd + languageName: node + linkType: hard + "denodeify@npm:^1.2.1": version: 1.2.1 resolution: "denodeify@npm:1.2.1" @@ -5467,6 +5800,13 @@ __metadata: languageName: node linkType: hard +"emoji-regex@npm:^10.3.0": + version: 10.6.0 + resolution: "emoji-regex@npm:10.6.0" + checksum: 10/98cc0b0e1daed1ed25afbf69dcb921fee00f712f51aab93aa1547e4e4e8171725cc4f0098aaa645b4f611a19da11ec9f4623eb6ff2b72314b39a8f2ae7c12bf2 + languageName: node + linkType: hard + "emoji-regex@npm:^8.0.0": version: 8.0.0 resolution: "emoji-regex@npm:8.0.0" @@ -5511,6 +5851,13 @@ __metadata: languageName: node linkType: hard +"entities@npm:^8.0.0": + version: 8.0.0 + resolution: "entities@npm:8.0.0" + checksum: 10/d6e2ba75e444fb101ee2fbb07c839e687306c8a509426b75186619c19196f97c1db9932ca083f823c03e4a20e7407b654aa34de8cbb7770468e20fb2d4573a0e + languageName: node + linkType: hard + "env-paths@npm:^2.2.0, env-paths@npm:^2.2.1": version: 2.2.1 resolution: "env-paths@npm:2.2.1" @@ -6274,6 +6621,13 @@ __metadata: languageName: node linkType: hard +"events@npm:^3.3.0": + version: 3.3.0 + resolution: "events@npm:3.3.0" + checksum: 10/a3d47e285e28d324d7180f1e493961a2bbb4cad6412090e4dec114f4db1f5b560c7696ee8e758f55e23913ede856e3689cd3aa9ae13c56b5d8314cd3b3ddd1be + languageName: node + linkType: hard + "execa@npm:^4.0.3": version: 4.1.0 resolution: "execa@npm:4.1.0" @@ -6434,6 +6788,13 @@ __metadata: languageName: node linkType: hard +"fd@npm:^0.0.3": + version: 0.0.3 + resolution: "fd@npm:0.0.3" + checksum: 10/1781abf7289a179c4f1689d52bfb9d603bea51ab68903eca801ce05ecca640d49b91456a5710882593478dc9de1fd21de661a6d0775722ac14f151d3d202e442 + languageName: node + linkType: hard + "fdir@npm:^6.5.0": version: 6.5.0 resolution: "fdir@npm:6.5.0" @@ -6559,6 +6920,16 @@ __metadata: languageName: node linkType: hard +"follow-redirects@npm:^1.16.0": + version: 1.16.0 + resolution: "follow-redirects@npm:1.16.0" + peerDependenciesMeta: + debug: + optional: true + checksum: 10/3fbe3d80b3b544c22705d837aa5d4a0d07a740d913534a2620b0a004c610af4148e3b58723536dd099aaa1c9d3a155964bde9665d6e5cb331460809a1fc572fd + languageName: node + linkType: hard + "for-each@npm:^0.3.3, for-each@npm:^0.3.5": version: 0.3.5 resolution: "for-each@npm:0.3.5" @@ -6578,6 +6949,19 @@ __metadata: languageName: node linkType: hard +"form-data@npm:^4.0.5": + version: 4.0.6 + resolution: "form-data@npm:4.0.6" + dependencies: + asynckit: "npm:^0.4.0" + combined-stream: "npm:^1.0.8" + es-set-tostringtag: "npm:^2.1.0" + hasown: "npm:^2.0.4" + mime-types: "npm:^2.1.35" + checksum: 10/de6614c8537c92fa5fa3ee7e827758f98f5a9c033f348b7de81855ef36e5cb867e75d9f405d9483ab8d724a4a20d4e79926a299fa8dbba38f530eb659f0884e4 + languageName: node + linkType: hard + "fresh@npm:~0.5.2": version: 0.5.2 resolution: "fresh@npm:0.5.2" @@ -6607,6 +6991,17 @@ __metadata: languageName: node linkType: hard +"fs-extra@npm:^11.2.0": + version: 11.3.6 + resolution: "fs-extra@npm:11.3.6" + dependencies: + graceful-fs: "npm:^4.2.0" + jsonfile: "npm:^6.0.1" + universalify: "npm:^2.0.0" + checksum: 10/34a981697b199002ea3b85c3483bcf353637d33ec4c922b136a8d8a597faa0495638d69b20c181448be041c31778c2bb7f7799d589819edf33da50f75b1abde9 + languageName: node + linkType: hard + "fs-extra@npm:^8.1.0": version: 8.1.0 resolution: "fs-extra@npm:8.1.0" @@ -6618,6 +7013,15 @@ __metadata: languageName: node linkType: hard +"fs-minipass@npm:^2.0.0": + version: 2.1.0 + resolution: "fs-minipass@npm:2.1.0" + dependencies: + minipass: "npm:^3.0.0" + checksum: 10/03191781e94bc9a54bd376d3146f90fe8e082627c502185dbf7b9b3032f66b0b142c1115f3b2cc5936575fc1b44845ce903dd4c21bec2a8d69f3bd56f9cee9ec + languageName: node + linkType: hard + "fs-minipass@npm:^3.0.0": version: 3.0.3 resolution: "fs-minipass@npm:3.0.3" @@ -6688,6 +7092,22 @@ __metadata: languageName: node linkType: hard +"gauge@npm:^4.0.3": + version: 4.0.4 + resolution: "gauge@npm:4.0.4" + dependencies: + aproba: "npm:^1.0.3 || ^2.0.0" + color-support: "npm:^1.1.3" + console-control-strings: "npm:^1.1.0" + has-unicode: "npm:^2.0.1" + signal-exit: "npm:^3.0.7" + string-width: "npm:^4.2.3" + strip-ansi: "npm:^6.0.1" + wide-align: "npm:^1.1.5" + checksum: 10/09535dd53b5ced6a34482b1fa9f3929efdeac02f9858569cde73cef3ed95050e0f3d095706c1689614059898924b7a74aa14042f51381a1ccc4ee5c29d2389c4 + languageName: node + linkType: hard + "generator-function@npm:^2.0.0": version: 2.0.1 resolution: "generator-function@npm:2.0.1" @@ -6709,6 +7129,13 @@ __metadata: languageName: node linkType: hard +"get-east-asian-width@npm:^1.0.0": + version: 1.6.0 + resolution: "get-east-asian-width@npm:1.6.0" + checksum: 10/3e5370b5df1f0020db711d8a3f9ee2cbfc9c7542daa99a699e9d7b9acf66e7868b89084741565a45d30d80afedf6e1218e0fb8bef7a583924a449c2816777380 + languageName: node + linkType: hard + "get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.2.7, get-intrinsic@npm:^1.3.0": version: 1.3.1 resolution: "get-intrinsic@npm:1.3.1" @@ -6951,7 +7378,7 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.1.3, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.10, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": +"graceful-fs@npm:^4.1.3, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.10, graceful-fs@npm:^4.2.3, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: 10/bf152d0ed1dc159239db1ba1f74fdbc40cb02f626770dcd5815c427ce0688c2635a06ed69af364396da4636d0408fcf7d4afdf7881724c3307e46aff30ca49e2 @@ -7027,6 +7454,13 @@ __metadata: languageName: node linkType: hard +"has-unicode@npm:^2.0.1": + version: 2.0.1 + resolution: "has-unicode@npm:2.0.1" + checksum: 10/041b4293ad6bf391e21c5d85ed03f412506d6623786b801c4ab39e4e6ca54993f13201bceb544d92963f9e0024e6e7fbf0cb1d84c9d6b31cb9c79c8c990d13d8 + languageName: node + linkType: hard + "hasown@npm:^2.0.2": version: 2.0.2 resolution: "hasown@npm:2.0.2" @@ -7036,6 +7470,15 @@ __metadata: languageName: node linkType: hard +"hasown@npm:^2.0.4": + version: 2.0.4 + resolution: "hasown@npm:2.0.4" + dependencies: + function-bind: "npm:^1.1.2" + checksum: 10/13823863ae48161068b4c51606a3128451c66f14545a5169d667fe9fca168dcd38c27570c7a299e32ef844b8da3d55def7fe88602f8970d4311fb543ee88001a + languageName: node + linkType: hard + "hermes-compiler@npm:250829098.0.10": version: 250829098.0.10 resolution: "hermes-compiler@npm:250829098.0.10" @@ -7043,6 +7486,13 @@ __metadata: languageName: node linkType: hard +"hermes-engine@npm:^0.11.0": + version: 0.11.0 + resolution: "hermes-engine@npm:0.11.0" + checksum: 10/d539efe55cea8633f93cc704163e265e947a1aa61d3ab5e89e3535e8d636d0b9c3500de2971b047c27ab059639053f4a2b6d73ceacafc823bc6cb09a0ce1badc + languageName: node + linkType: hard + "hermes-eslint@npm:^0.26.0": version: 0.26.0 resolution: "hermes-eslint@npm:0.26.0" @@ -7143,6 +7593,15 @@ __metadata: languageName: node linkType: hard +"html-encoding-sniffer@npm:^6.0.0": + version: 6.0.0 + resolution: "html-encoding-sniffer@npm:6.0.0" + dependencies: + "@exodus/bytes": "npm:^1.6.0" + checksum: 10/97392e45d8aff57f180f62a1b12e62201c8451af68424b8bc3196f78e273891f2df285e5be43a3f28c7ba4badf9524ef305db65c4e4935a9e796afc86d9654b8 + languageName: node + linkType: hard + "html-escaper@npm:^2.0.0": version: 2.0.2 resolution: "html-escaper@npm:2.0.2" @@ -7180,6 +7639,16 @@ __metadata: languageName: node linkType: hard +"https-proxy-agent@npm:^5.0.1": + version: 5.0.1 + resolution: "https-proxy-agent@npm:5.0.1" + dependencies: + agent-base: "npm:6" + debug: "npm:4" + checksum: 10/f0dce7bdcac5e8eaa0be3c7368bb8836ed010fb5b6349ffb412b172a203efe8f807d9a6681319105ea1b6901e1972c7b5ea899672a7b9aad58309f766dcbe0df + languageName: node + linkType: hard + "https-proxy-agent@npm:^7.0.1, https-proxy-agent@npm:^7.0.5": version: 7.0.6 resolution: "https-proxy-agent@npm:7.0.6" @@ -7222,7 +7691,7 @@ __metadata: languageName: node linkType: hard -"ieee754@npm:^1.1.13": +"ieee754@npm:^1.1.13, ieee754@npm:^1.2.1": version: 1.2.1 resolution: "ieee754@npm:1.2.1" checksum: 10/d9f2557a59036f16c282aaeb107832dc957a93d73397d89bbad4eb1130560560eb695060145e8e6b3b498b15ab95510226649a0b8f52ae06583575419fe10fc4 @@ -7324,7 +7793,7 @@ __metadata: languageName: node linkType: hard -"ini@npm:^1.3.4": +"ini@npm:^1.3.4, ini@npm:~1.3.0": version: 1.3.8 resolution: "ini@npm:1.3.8" checksum: 10/314ae176e8d4deb3def56106da8002b462221c174ddb7ce0c49ee72c8cd1f9044f7b10cc555a7d8850982c3b9ca96fc212122749f5234bc2b6fb05fb942ed566 @@ -7655,6 +8124,13 @@ __metadata: languageName: node linkType: hard +"is-potential-custom-element-name@npm:^1.0.1": + version: 1.0.1 + resolution: "is-potential-custom-element-name@npm:1.0.1" + checksum: 10/ced7bbbb6433a5b684af581872afe0e1767e2d1146b2207ca0068a648fb5cab9d898495d1ac0583524faaf24ca98176a7d9876363097c2d14fee6dd324f3a1ab + languageName: node + linkType: hard + "is-regex@npm:^1.2.1": version: 1.2.1 resolution: "is-regex@npm:1.2.1" @@ -8426,6 +8902,40 @@ __metadata: languageName: node linkType: hard +"jsdom@npm:^29.0.1": + version: 29.1.1 + resolution: "jsdom@npm:29.1.1" + dependencies: + "@asamuzakjp/css-color": "npm:^5.1.11" + "@asamuzakjp/dom-selector": "npm:^7.1.1" + "@bramus/specificity": "npm:^2.4.2" + "@csstools/css-syntax-patches-for-csstree": "npm:^1.1.3" + "@exodus/bytes": "npm:^1.15.0" + css-tree: "npm:^3.2.1" + data-urls: "npm:^7.0.0" + decimal.js: "npm:^10.6.0" + html-encoding-sniffer: "npm:^6.0.0" + is-potential-custom-element-name: "npm:^1.0.1" + lru-cache: "npm:^11.3.5" + parse5: "npm:^8.0.1" + saxes: "npm:^6.0.0" + symbol-tree: "npm:^3.2.4" + tough-cookie: "npm:^6.0.1" + undici: "npm:^7.25.0" + w3c-xmlserializer: "npm:^5.0.0" + webidl-conversions: "npm:^8.0.1" + whatwg-mimetype: "npm:^5.0.0" + whatwg-url: "npm:^16.0.1" + xml-name-validator: "npm:^5.0.0" + peerDependencies: + canvas: ^3.0.0 + peerDependenciesMeta: + canvas: + optional: true + checksum: 10/344aed7f91839b6c7d1b40778c5542d6ded7d42d88e1b787e10bf12d4ccd65464a5f23f774eb84350885c75a48efc99f6972adbb94dffe324a1b065d3650843c + languageName: node + linkType: hard + "jsesc@npm:^3.0.2, jsesc@npm:~3.1.0": version: 3.1.0 resolution: "jsesc@npm:3.1.0" @@ -8789,6 +9299,13 @@ __metadata: languageName: node linkType: hard +"lru-cache@npm:^11.3.5": + version: 11.5.1 + resolution: "lru-cache@npm:11.5.1" + checksum: 10/02c4f73967d91fb101f4accf8ebac9e0541e08e16d987bdb9e9737f13e5f2c4bc33c593b98ec30e4486bf899bc97edb36fbd133684b36087336559e41edafdea + languageName: node + linkType: hard + "lru-cache@npm:^5.1.1": version: 5.1.1 resolution: "lru-cache@npm:5.1.1" @@ -8937,6 +9454,13 @@ __metadata: languageName: node linkType: hard +"mdn-data@npm:2.27.1": + version: 2.27.1 + resolution: "mdn-data@npm:2.27.1" + checksum: 10/5046dc83a961b8ea82a5d6d8331d07df6b15faec61519ce2f83e49766702358e7e6af96413be977ff89080534be6762c1d5963b5dd1180c208a47c0a663226b2 + languageName: node + linkType: hard + "media-typer@npm:0.3.0": version: 0.3.0 resolution: "media-typer@npm:0.3.0" @@ -8951,6 +9475,15 @@ __metadata: languageName: node linkType: hard +"memory-stream@npm:^1.0.0": + version: 1.0.0 + resolution: "memory-stream@npm:1.0.0" + dependencies: + readable-stream: "npm:^3.4.0" + checksum: 10/c1b59b4e3c36bf39aea7f6ef332c570ce12f645392574e8574788dc01e874e85fba60c4f3385d90528b4551ad3c33dffd518d387d50554ef12da3c904538660c + languageName: node + linkType: hard + "meow@npm:^10.1.3": version: 10.1.5 resolution: "meow@npm:10.1.5" @@ -9720,7 +10253,7 @@ __metadata: languageName: node linkType: hard -"mime-types@npm:^2.1.27, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": +"mime-types@npm:^2.1.27, mime-types@npm:^2.1.35, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": version: 2.1.35 resolution: "mime-types@npm:2.1.35" dependencies: @@ -9756,6 +10289,15 @@ __metadata: languageName: node linkType: hard +"mime@npm:^3.0.0": + version: 3.0.0 + resolution: "mime@npm:3.0.0" + bin: + mime: cli.js + checksum: 10/b2d31580deb58be89adaa1877cbbf152b7604b980fd7ef8f08b9e96bfedf7d605d9c23a8ba62aa12c8580b910cd7c1d27b7331d0f40f7a14e17d5a0bbec3b49f + languageName: node + linkType: hard + "mimic-fn@npm:^2.1.0": version: 2.1.0 resolution: "mimic-fn@npm:2.1.0" @@ -9900,6 +10442,13 @@ __metadata: languageName: node linkType: hard +"minipass@npm:^5.0.0": + version: 5.0.0 + resolution: "minipass@npm:5.0.0" + checksum: 10/61682162d29f45d3152b78b08bab7fb32ca10899bc5991ffe98afc18c9e9543bd1e3be94f8b8373ba6262497db63607079dc242ea62e43e7b2270837b7347c93 + languageName: node + linkType: hard + "minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4, minipass@npm:^7.1.2, minipass@npm:^7.1.3": version: 7.1.3 resolution: "minipass@npm:7.1.3" @@ -9907,6 +10456,16 @@ __metadata: languageName: node linkType: hard +"minizlib@npm:^2.1.1": + version: 2.1.2 + resolution: "minizlib@npm:2.1.2" + dependencies: + minipass: "npm:^3.0.0" + yallist: "npm:^4.0.0" + checksum: 10/ae0f45436fb51344dcb87938446a32fbebb540d0e191d63b35e1c773d47512e17307bf54aa88326cc6d176594d00e4423563a091f7266c2f9a6872cdc1e234d1 + languageName: node + linkType: hard + "minizlib@npm:^3.0.1, minizlib@npm:^3.1.0": version: 3.1.0 resolution: "minizlib@npm:3.1.0" @@ -9916,7 +10475,7 @@ __metadata: languageName: node linkType: hard -"mkdirp@npm:^1.0.4": +"mkdirp@npm:^1.0.3, mkdirp@npm:^1.0.4": version: 1.0.4 resolution: "mkdirp@npm:1.0.4" bin: @@ -9990,6 +10549,13 @@ __metadata: languageName: node linkType: hard +"node-api-headers@npm:^1.1.0": + version: 1.9.0 + resolution: "node-api-headers@npm:1.9.0" + checksum: 10/9a46d37aaf7e1c0e28ba6593978bc480ae1ba312863d30eb033e35a4e21d9c35d628bf5c5297f0671102c09741a896d0825f7a3477c86e83d248c0548712bdba + languageName: node + linkType: hard + "node-exports-info@npm:^1.6.0": version: 1.6.0 resolution: "node-exports-info@npm:1.6.0" @@ -10094,6 +10660,18 @@ __metadata: languageName: node linkType: hard +"npmlog@npm:^6.0.2": + version: 6.0.2 + resolution: "npmlog@npm:6.0.2" + dependencies: + are-we-there-yet: "npm:^3.0.0" + console-control-strings: "npm:^1.1.0" + gauge: "npm:^4.0.3" + set-blocking: "npm:^2.0.0" + checksum: 10/82b123677e62deb9e7472e27b92386c09e6e254ee6c8bcd720b3011013e4168bc7088e984f4fbd53cb6e12f8b4690e23e4fa6132689313e0d0dc4feea45489bb + languageName: node + linkType: hard + "nth-check@npm:^2.0.1": version: 2.1.1 resolution: "nth-check@npm:2.1.1" @@ -10445,6 +11023,15 @@ __metadata: languageName: node linkType: hard +"parse5@npm:^8.0.1": + version: 8.0.1 + resolution: "parse5@npm:8.0.1" + dependencies: + entities: "npm:^8.0.0" + checksum: 10/671dedfe7cbf4714414317bc8c6b2a14c61ef44f8fd90c983b5b1870653af5aa2e3b4e25e38e9538a7120ea2b688c50908830da2bd0930d8fd4bce34aed024eb + languageName: node + linkType: hard + "parseurl@npm:~1.3.3": version: 1.3.3 resolution: "parseurl@npm:1.3.3" @@ -10648,6 +11235,13 @@ __metadata: languageName: node linkType: hard +"process@npm:^0.11.10": + version: 0.11.10 + resolution: "process@npm:0.11.10" + checksum: 10/dbaa7e8d1d5cf375c36963ff43116772a989ef2bb47c9bdee20f38fd8fc061119cf38140631cf90c781aca4d3f0f0d2c834711952b728953f04fd7d238f59f5b + languageName: node + linkType: hard + "promise@npm:^8.3.0": version: 8.3.0 resolution: "promise@npm:8.3.0" @@ -10678,6 +11272,13 @@ __metadata: languageName: node linkType: hard +"proxy-from-env@npm:^2.1.0": + version: 2.1.0 + resolution: "proxy-from-env@npm:2.1.0" + checksum: 10/fbbaf4dab2a6231dc9e394903a5f66f20475e36b734335790b46feb9da07c37d6b32e2c02e3e2ea4d4b23774c53d8562e5b7cc73282cb43f4a597b7eacaee2ee + languageName: node + linkType: hard + "pump@npm:^3.0.0": version: 3.0.4 resolution: "pump@npm:3.0.4" @@ -10688,7 +11289,7 @@ __metadata: languageName: node linkType: hard -"punycode@npm:^2.1.0": +"punycode@npm:^2.1.0, punycode@npm:^2.3.1": version: 2.3.1 resolution: "punycode@npm:2.3.1" checksum: 10/febdc4362bead22f9e2608ff0171713230b57aff9dddc1c273aa2a651fbd366f94b7d6a71d78342a7c0819906750351ca7f2edd26ea41b626d87d6a13d1bd059 @@ -10779,6 +11380,20 @@ __metadata: languageName: node linkType: hard +"rc@npm:^1.2.7": + version: 1.2.8 + resolution: "rc@npm:1.2.8" + dependencies: + deep-extend: "npm:^0.6.0" + ini: "npm:~1.3.0" + minimist: "npm:^1.2.0" + strip-json-comments: "npm:~2.0.1" + bin: + rc: ./cli.js + checksum: 10/5c4d72ae7eec44357171585938c85ce066da8ca79146b5635baf3d55d74584c92575fa4e2c9eac03efbed3b46a0b2e7c30634c012b4b4fa40d654353d3c163eb + languageName: node + linkType: hard + "react-devtools-core@npm:^6.1.5": version: 6.1.5 resolution: "react-devtools-core@npm:6.1.5" @@ -10868,6 +11483,9 @@ __metadata: "@types/react-test-renderer": "npm:^19.1.0" "@types/semver": "npm:7.7.1" babel-plugin-module-resolver: "npm:^4.1.0" + chalk: "npm:^5.3.0" + cmake-js: "npm:^7.3.1" + commander: "npm:^14.0.0" commitlint: "npm:17.0.2" del-cli: "npm:^5.1.0" eslint: "npm:^8.57.0" @@ -10884,6 +11502,7 @@ __metadata: eslint-plugin-react-hooks: "npm:^4.6.0" eslint-plugin-standard: "npm:^5.0.0" eslint-plugin-tsdoc: "npm:^0.2.17" + hermes-engine: "npm:^0.11.0" jest: "npm:^29.7.0" prettier: "npm:^3.3.3" react: "npm:19.2.3" @@ -10892,6 +11511,7 @@ __metadata: semver: "npm:^7.7.3" turbo: "npm:^1.10.7" typescript: "npm:~6.0.3" + wpt-runner: "npm:^7.0.0" peerDependencies: react: "*" react-native: "*" @@ -11207,7 +11827,7 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:3, readable-stream@npm:^3.0.0, readable-stream@npm:^3.4.0": +"readable-stream@npm:3, readable-stream@npm:^3.0.0, readable-stream@npm:^3.4.0, readable-stream@npm:^3.6.0": version: 3.6.2 resolution: "readable-stream@npm:3.6.2" dependencies: @@ -11218,6 +11838,19 @@ __metadata: languageName: node linkType: hard +"readable-stream@npm:^4.2.0": + version: 4.7.0 + resolution: "readable-stream@npm:4.7.0" + dependencies: + abort-controller: "npm:^3.0.0" + buffer: "npm:^6.0.3" + events: "npm:^3.3.0" + process: "npm:^0.11.10" + string_decoder: "npm:^1.3.0" + checksum: 10/bdf096c8ff59452ce5d08f13da9597f9fcfe400b4facfaa88e74ec057e5ad1fdfa140ffe28e5ed806cf4d2055f0b812806e962bca91dce31bc4cef08e53be3a4 + languageName: node + linkType: hard + "readable-stream@npm:~2.3.6": version: 2.3.8 resolution: "readable-stream@npm:2.3.8" @@ -11605,6 +12238,15 @@ __metadata: languageName: node linkType: hard +"saxes@npm:^6.0.0": + version: 6.0.0 + resolution: "saxes@npm:6.0.0" + dependencies: + xmlchars: "npm:^2.2.0" + checksum: 10/97b50daf6ca3a153e89842efa18a862e446248296622b7473c169c84c823ee8a16e4a43bac2f73f11fc8cb9168c73fbb0d73340f26552bac17970e9052367aa9 + languageName: node + linkType: hard + "scheduler@npm:0.27.0, scheduler@npm:^0.27.0": version: 0.27.0 resolution: "scheduler@npm:0.27.0" @@ -11934,6 +12576,13 @@ __metadata: languageName: node linkType: hard +"source-map-js@npm:^1.2.1": + version: 1.2.1 + resolution: "source-map-js@npm:1.2.1" + checksum: 10/ff9d8c8bf096d534a5b7707e0382ef827b4dd360a577d3f34d2b9f48e12c9d230b5747974ee7c607f0df65113732711bb701fe9ece3c7edbd43cb2294d707df3 + languageName: node + linkType: hard + "source-map-support@npm:0.5.13": version: 0.5.13 resolution: "source-map-support@npm:0.5.13" @@ -12044,6 +12693,25 @@ __metadata: languageName: node linkType: hard +"st@npm:^3.0.3": + version: 3.0.3 + resolution: "st@npm:3.0.3" + dependencies: + bl: "npm:^6.1.0" + fd: "npm:^0.0.3" + graceful-fs: "npm:^4.2.3" + lru-cache: "npm:^11.1.0" + mime: "npm:^3.0.0" + negotiator: "npm:^1.0.0" + dependenciesMeta: + graceful-fs: + optional: true + bin: + st: bin/server.js + checksum: 10/77d6d76ab7f81d070a1709653096b29cf37eafb0d381dddfcb91fe87b6e6b573b7270f1a8c93b8ff1d9add45154a19bbf0ac165ff02f5b22a6b10e2445254a7c + languageName: node + linkType: hard + "stack-utils@npm:^2.0.3": version: 2.0.6 resolution: "stack-utils@npm:2.0.6" @@ -12124,7 +12792,7 @@ __metadata: languageName: node linkType: hard -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" dependencies: @@ -12146,6 +12814,17 @@ __metadata: languageName: node linkType: hard +"string-width@npm:^7.0.0, string-width@npm:^7.2.0": + version: 7.2.0 + resolution: "string-width@npm:7.2.0" + dependencies: + emoji-regex: "npm:^10.3.0" + get-east-asian-width: "npm:^1.0.0" + strip-ansi: "npm:^7.1.0" + checksum: 10/42f9e82f61314904a81393f6ef75b832c39f39761797250de68c041d8ba4df2ef80db49ab6cd3a292923a6f0f409b8c9980d120f7d32c820b4a8a84a2598a295 + languageName: node + linkType: hard + "string.prototype.matchall@npm:^4.0.12": version: 4.0.12 resolution: "string.prototype.matchall@npm:4.0.12" @@ -12215,7 +12894,7 @@ __metadata: languageName: node linkType: hard -"string_decoder@npm:^1.1.1": +"string_decoder@npm:^1.1.1, string_decoder@npm:^1.3.0": version: 1.3.0 resolution: "string_decoder@npm:1.3.0" dependencies: @@ -12251,7 +12930,7 @@ __metadata: languageName: node linkType: hard -"strip-ansi@npm:^7.0.1": +"strip-ansi@npm:^7.0.1, strip-ansi@npm:^7.1.0": version: 7.2.0 resolution: "strip-ansi@npm:7.2.0" dependencies: @@ -12304,6 +12983,13 @@ __metadata: languageName: node linkType: hard +"strip-json-comments@npm:~2.0.1": + version: 2.0.1 + resolution: "strip-json-comments@npm:2.0.1" + checksum: 10/1074ccb63270d32ca28edfb0a281c96b94dc679077828135141f27d52a5a398ef5e78bcf22809d23cadc2b81dfbe345eb5fd8699b385c8b1128907dec4a7d1e1 + languageName: node + linkType: hard + "strnum@npm:^1.0.5": version: 1.1.2 resolution: "strnum@npm:1.1.2" @@ -12345,6 +13031,13 @@ __metadata: languageName: node linkType: hard +"symbol-tree@npm:^3.2.4": + version: 3.2.4 + resolution: "symbol-tree@npm:3.2.4" + checksum: 10/c09a00aadf279d47d0c5c46ca3b6b2fbaeb45f0a184976d599637d412d3a70bbdc043ff33effe1206dea0e36e0ad226cb957112e7ce9a4bf2daedf7fa4f85c53 + languageName: node + linkType: hard + "synckit@npm:^0.11.12": version: 0.11.12 resolution: "synckit@npm:0.11.12" @@ -12354,6 +13047,20 @@ __metadata: languageName: node linkType: hard +"tar@npm:^6.2.0": + version: 6.2.1 + resolution: "tar@npm:6.2.1" + dependencies: + chownr: "npm:^2.0.0" + fs-minipass: "npm:^2.0.0" + minipass: "npm:^5.0.0" + minizlib: "npm:^2.1.1" + mkdirp: "npm:^1.0.3" + yallist: "npm:^4.0.0" + checksum: 10/bfbfbb2861888077fc1130b84029cdc2721efb93d1d1fb80f22a7ac3a98ec6f8972f29e564103bbebf5e97be67ebc356d37fa48dbc4960600a1eb7230fbd1ea0 + languageName: node + linkType: hard + "tar@npm:^7.5.4": version: 7.5.13 resolution: "tar@npm:7.5.13" @@ -12449,6 +13156,24 @@ __metadata: languageName: node linkType: hard +"tldts-core@npm:^7.4.5": + version: 7.4.5 + resolution: "tldts-core@npm:7.4.5" + checksum: 10/76bafd941c3797a7d17bf97a19d4c9a5b613212f502a8bf14d59e7e0b374ab2552989b768e90766d34880e85aee7cfe2133831bb30a3835432934cf446b6733f + languageName: node + linkType: hard + +"tldts@npm:^7.0.5": + version: 7.4.5 + resolution: "tldts@npm:7.4.5" + dependencies: + tldts-core: "npm:^7.4.5" + bin: + tldts: bin/cli.js + checksum: 10/3542158bfd7c86ede7b1236c4b1fe6afc5858c17a2a2033a702afaa5b4f2614b180059b5a516159e032d93aaf82dfdbf2c91eca0d369bfed09336ba6a6c4f4f9 + languageName: node + linkType: hard + "tmpl@npm:1.0.5": version: 1.0.5 resolution: "tmpl@npm:1.0.5" @@ -12472,6 +13197,24 @@ __metadata: languageName: node linkType: hard +"tough-cookie@npm:^6.0.1": + version: 6.0.1 + resolution: "tough-cookie@npm:6.0.1" + dependencies: + tldts: "npm:^7.0.5" + checksum: 10/915b1167e0630598eb0644e8bc089ddc28a23bf05f3c329a4a0d879c6b9801a2603be65acb06b5d2dd0f589cabb06bb638837f8222dd82a7023655f07269451a + languageName: node + linkType: hard + +"tr46@npm:^6.0.0": + version: 6.0.0 + resolution: "tr46@npm:6.0.0" + dependencies: + punycode: "npm:^2.3.1" + checksum: 10/e6d402eb2b780a40042f327f77b4ae316da1d2b18a29c16e48c239f5267c6005bbf780f854179cfae62b02dfaa70b0e9aad8f0078ccc4225f5b3b3b131928e8f + languageName: node + linkType: hard + "trim-newlines@npm:^3.0.0": version: 3.0.1 resolution: "trim-newlines@npm:3.0.1" @@ -12815,6 +13558,13 @@ __metadata: languageName: node linkType: hard +"undici@npm:^7.25.0": + version: 7.28.0 + resolution: "undici@npm:7.28.0" + checksum: 10/154423b280d623278a61decb437f8a7e581fb18b8c95556ef956b32a58cd668eadbb812d28e20678cb2dc545a566f35a3afc0962307ca801da30f4741117986d + languageName: node + linkType: hard + "unicode-canonical-property-names-ecmascript@npm:^2.0.0": version: 2.0.1 resolution: "unicode-canonical-property-names-ecmascript@npm:2.0.1" @@ -12899,6 +13649,13 @@ __metadata: languageName: node linkType: hard +"url-join@npm:^4.0.1": + version: 4.0.1 + resolution: "url-join@npm:4.0.1" + checksum: 10/b53b256a9a36ed6b0f6768101e78ca97f32d7b935283fd29ce19d0bbfb6f88aa80aa6c03fd87f2f8978ab463a6539f597a63051e7086f3379685319a7495f709 + languageName: node + linkType: hard + "use-latest-callback@npm:^0.2.4": version: 0.2.6 resolution: "use-latest-callback@npm:0.2.6" @@ -12982,6 +13739,15 @@ __metadata: languageName: node linkType: hard +"w3c-xmlserializer@npm:^5.0.0": + version: 5.0.0 + resolution: "w3c-xmlserializer@npm:5.0.0" + dependencies: + xml-name-validator: "npm:^5.0.0" + checksum: 10/d78f59e6b4f924aa53b6dfc56949959229cae7fe05ea9374eb38d11edcec01398b7f5d7a12576bd5acc57ff446abb5c9115cd83b9d882555015437cf858d42f0 + languageName: node + linkType: hard + "walker@npm:^1.0.7, walker@npm:^1.0.8": version: 1.0.8 resolution: "walker@npm:1.0.8" @@ -13007,6 +13773,13 @@ __metadata: languageName: node linkType: hard +"webidl-conversions@npm:^8.0.1": + version: 8.0.1 + resolution: "webidl-conversions@npm:8.0.1" + checksum: 10/0f7007311f1fc257a8e406dd236f13b61fb57cf0fddb476aec33457d2d0add2d012d6df0eeb00934399238e3f3b9dad30f59dc6ac83024ae0ebd5a518bf365e8 + languageName: node + linkType: hard + "whatwg-fetch@npm:^3.0.0": version: 3.6.20 resolution: "whatwg-fetch@npm:3.6.20" @@ -13014,6 +13787,24 @@ __metadata: languageName: node linkType: hard +"whatwg-mimetype@npm:^5.0.0": + version: 5.0.0 + resolution: "whatwg-mimetype@npm:5.0.0" + checksum: 10/a2d5da445f671ed34010b45283ffb9ba3c68c695b8ec91f7400cfc9149c35eb2bc47bd2c39bbe8e026786b955ace03402ba2e5cfde4955434a3ec3c511a85d0a + languageName: node + linkType: hard + +"whatwg-url@npm:^16.0.0, whatwg-url@npm:^16.0.1": + version: 16.0.1 + resolution: "whatwg-url@npm:16.0.1" + dependencies: + "@exodus/bytes": "npm:^1.11.0" + tr46: "npm:^6.0.0" + webidl-conversions: "npm:^8.0.1" + checksum: 10/221cc15ef89288dc1fafdb409352c62ab12ba9ff7f0753e925d8799c87b20371f3bc762dc0a8a5b9c23cddc4b1860537fc6c1bcc9d816ace9b3d3c47212cd163 + languageName: node + linkType: hard + "which-boxed-primitive@npm:^1.1.0, which-boxed-primitive@npm:^1.1.1": version: 1.1.1 resolution: "which-boxed-primitive@npm:1.1.1" @@ -13104,6 +13895,15 @@ __metadata: languageName: node linkType: hard +"wide-align@npm:^1.1.5": + version: 1.1.5 + resolution: "wide-align@npm:1.1.5" + dependencies: + string-width: "npm:^1.0.2 || 2 || 3 || 4" + checksum: 10/d5f8027b9a8255a493a94e4ec1b74a27bff6679d5ffe29316a3215e4712945c84ef73ca4045c7e20ae7d0c72f5f57f296e04a4928e773d4276a2f1222e4c2e99 + languageName: node + linkType: hard + "word-wrap@npm:^1.2.5": version: 1.2.5 resolution: "word-wrap@npm:1.2.5" @@ -13111,6 +13911,19 @@ __metadata: languageName: node linkType: hard +"wpt-runner@npm:^7.0.0": + version: 7.0.0 + resolution: "wpt-runner@npm:7.0.0" + dependencies: + jsdom: "npm:^29.0.1" + st: "npm:^3.0.3" + yargs: "npm:^18.0.0" + bin: + wpt-runner: bin/wpt-runner.js + checksum: 10/352c5f629c3495900f24378938eb8de062baca44740e499ea53ecebc7c553a17d9bdb6f7c729d5c2daadddfc32075889de0ee97dfb11a8f8ae5268e6b975e7bd + languageName: node + linkType: hard + "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0, wrap-ansi@npm:^7.0.0": version: 7.0.0 resolution: "wrap-ansi@npm:7.0.0" @@ -13144,6 +13957,17 @@ __metadata: languageName: node linkType: hard +"wrap-ansi@npm:^9.0.0": + version: 9.0.2 + resolution: "wrap-ansi@npm:9.0.2" + dependencies: + ansi-styles: "npm:^6.2.1" + string-width: "npm:^7.0.0" + strip-ansi: "npm:^7.1.0" + checksum: 10/f3907e1ea9717404ca53a338fa5a017c2121550c3a5305180e2bc08c03e21aa45068df55b0d7676bf57be1880ba51a84458c17241ebedea485fafa9ef16b4024 + languageName: node + linkType: hard + "wrappy@npm:1": version: 1.0.2 resolution: "wrappy@npm:1.0.2" @@ -13195,6 +14019,13 @@ __metadata: languageName: node linkType: hard +"xml-name-validator@npm:^5.0.0": + version: 5.0.0 + resolution: "xml-name-validator@npm:5.0.0" + checksum: 10/43f30f3f6786e406dd665acf08cd742d5f8a46486bd72517edb04b27d1bcd1599664c2a4a99fc3f1e56a3194bff588b12f178b7972bc45c8047bdc4c3ac8d4a1 + languageName: node + linkType: hard + "xml2js@npm:0.6.0": version: 0.6.0 resolution: "xml2js@npm:0.6.0" @@ -13219,6 +14050,13 @@ __metadata: languageName: node linkType: hard +"xmlchars@npm:^2.2.0": + version: 2.2.0 + resolution: "xmlchars@npm:2.2.0" + checksum: 10/4ad5924974efd004a47cce6acf5c0269aee0e62f9a805a426db3337af7bcbd331099df174b024ace4fb18971b8a56de386d2e73a1c4b020e3abd63a4a9b917f1 + languageName: node + linkType: hard + "xtend@npm:~4.0.1": version: 4.0.2 resolution: "xtend@npm:4.0.2" @@ -13294,6 +14132,13 @@ __metadata: languageName: node linkType: hard +"yargs-parser@npm:^22.0.0": + version: 22.0.0 + resolution: "yargs-parser@npm:22.0.0" + checksum: 10/f13c42bad6ebed1a587a72f2db5694f5fa772bcaf409a701691d13cf74eb5adfcf61a2611de08807e319b829d3e5e6e1578b16ebe174cae8e8be3bf7b8e7a19e + languageName: node + linkType: hard + "yargs@npm:^15.1.0": version: 15.4.1 resolution: "yargs@npm:15.4.1" @@ -13328,6 +14173,35 @@ __metadata: languageName: node linkType: hard +"yargs@npm:^17.7.2": + version: 17.7.3 + resolution: "yargs@npm:17.7.3" + dependencies: + cliui: "npm:^8.0.1" + escalade: "npm:^3.1.1" + get-caller-file: "npm:^2.0.5" + require-directory: "npm:^2.1.1" + string-width: "npm:^4.2.3" + y18n: "npm:^5.0.5" + yargs-parser: "npm:^21.1.1" + checksum: 10/a3826798c03b159e139d0580a3b2733953889a9a1bac8e4e1ca7a1a249b55315b213c323a6a1dbdb305f6e59496a9eaa810742c87e34abcf1a0584d8f59212a1 + languageName: node + linkType: hard + +"yargs@npm:^18.0.0": + version: 18.0.0 + resolution: "yargs@npm:18.0.0" + dependencies: + cliui: "npm:^9.0.1" + escalade: "npm:^3.1.1" + get-caller-file: "npm:^2.0.5" + string-width: "npm:^7.2.0" + y18n: "npm:^5.0.5" + yargs-parser: "npm:^22.0.0" + checksum: 10/5af36234871390386b31cac99f00e79fcbc2ead858a61b30a8ca381c5fde5df8af0b407c36b000d3f774bcbe4aec5833f2f1c915f6ddc49ce97b78176b651801 + languageName: node + linkType: hard + "yn@npm:3.1.1": version: 3.1.1 resolution: "yn@npm:3.1.1"