Skip to content

Commit

Permalink
Merge pull request #13 from JoaquinBCh/refactor/decoupling
Browse files Browse the repository at this point in the history
Decouple the Player from the Web Application
  • Loading branch information
englishm authored Jan 7, 2025
2 parents fddb003 + adfb058 commit 03d6329
Show file tree
Hide file tree
Showing 21 changed files with 7,424 additions and 2,681 deletions.
1 change: 1 addition & 0 deletions lib/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ module.exports = {
plugins: ["@typescript-eslint", "prettier", "solid"],
root: true,
env: {
commonjs: true,
browser: true,
es2022: true,
worker: true,
Expand Down
2 changes: 2 additions & 0 deletions lib/common/async.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export class Watch<T> {

constructor(init: T) {
this.#next = new Deferred<WatchNext<T>>()
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.#current = [init, this.#next.promise]
}

Expand All @@ -44,6 +45,7 @@ export class Watch<T> {
}

const next = new Deferred<WatchNext<T>>()
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.#current = [v, next.promise]
this.#next.resolve(this.#current)
this.#next = next
Expand Down
2 changes: 1 addition & 1 deletion lib/contribute/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export class Container {
this.#track = this.#mp4.addTrack(options)
if (!this.#track) throw new Error("failed to initialize MP4 track")

const buffer = MP4.ISOFile.writeInitializationSegment(this.#mp4.ftyp!, this.#mp4.moov!, 0, 0)
const buffer = MP4.ISOFile.writeInitializationSegment(this.#mp4.ftyp, this.#mp4.moov, 0, 0)
const data = new Uint8Array(buffer)

controller.enqueue({
Expand Down
4 changes: 2 additions & 2 deletions lib/media/mp4/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ MP4.BoxParser.dOpsBox.prototype.write = function (stream: MP4.Stream) {
stream.writeUint8(this.ChannelMappingFamily)

if (this.ChannelMappingFamily !== 0) {
stream.writeUint8(this.StreamCount!)
stream.writeUint8(this.CoupledCount!)
stream.writeUint8(this.StreamCount)
stream.writeUint8(this.CoupledCount)
for (const mapping of this.ChannelMapping!) {
stream.writeUint8(mapping)
}
Expand Down
48 changes: 40 additions & 8 deletions lib/package.json
Original file line number Diff line number Diff line change
@@ -1,29 +1,61 @@
{
"name": "@kixelated/moq",
"type": "module",
"version": "0.1.4",
"name": "moq-player",
"version": "0.0.1",
"description": "Media over QUIC library",
"license": "(MIT OR Apache-2.0)",
"repository": "github:kixelated/moq-js",
"entry": "playback/index.ts",
"main": "dist/moq-player.cjs.js",
"module": "dist/moq-player.esm.js",
"iife": "dist/moq-player.iife.js",
"types": "dist/types/moq-player.d.ts",
"scripts": {
"build": "tsc -b && cp ../LICENSE* ./dist && cp ./README.md ./dist && cp ./package.json ./dist",
"lint": "eslint .",
"build": "rollup -c",
"dev": "rollup -c -w",
"lint": "eslint . --ext .js,.ts,.jsx,.tsx",
"fmt": "prettier --write ."
},
"devDependencies": {
"@babel/core": "^7.26.0",
"@babel/preset-env": "^7.26.0",
"@babel/preset-typescript": "^7.26.0",
"@rollup/plugin-babel": "^6.0.4",
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^12.1.1",
"@types/audioworklet": "^0.0.50",
"@types/dom-mediacapture-transform": "^0.1.6",
"@types/dom-webcodecs": "^0.1.8",
"@typescript/lib-dom": "npm:@types/web@^0.0.115",
"@typescript-eslint/eslint-plugin": "^6.4.0",
"@typescript-eslint/parser": "^6.4.0",
"@typescript/lib-dom": "npm:@types/web@^0.0.115",
"cross-env": "^7.0.2",
"eslint": "^8.47.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.0",
"npm-run-all": "^4.1.5",
"prettier": "^3.0.1",
"typescript": "^5.1.6"
"rollup": "^4.28.0",
"rollup-plugin-sourcemaps": "^0.6.2",
"rollup-plugin-web-worker-loader": "github:montevideo-tech/rollup-plugin-web-worker-loader",
"tslib": "^2.8.1",
"typescript": "^5.7.2"
},
"dependencies": {
"mp4box": "^0.5.2"
},
"browserslist": {
"production": [
"chrome >= 97",
"edge >= 98",
"firefox >= 130",
"opera >= 83",
"safari >= 18"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
9 changes: 2 additions & 7 deletions lib/playback/audio.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
/// <reference types="vite/client" />

import * as Message from "./worker/message"

// This is a non-standard way of importing worklet/workers.
// Unfortunately, it's the only option because of a Vite bug: https://github.com/vitejs/vite/issues/11823
import workletURL from "./worklet/index.ts?worker&url"
import registerMyAudioWorklet from "audio-worklet:./worklet/index.ts"

// NOTE: This must be on the main thread
export class Audio {
Expand All @@ -25,8 +21,7 @@ export class Audio {

private async load(config: Message.ConfigAudio): Promise<AudioWorkletNode> {
// Load the worklet source code.
await this.context.audioWorklet.addModule(workletURL)

await registerMyAudioWorklet(this.context)
const volume = this.context.createGain()
volume.gain.value = 2.0

Expand Down
9 changes: 4 additions & 5 deletions lib/playback/backend.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/// <reference types="vite/client" />

import * as Message from "./worker/message"
import { Audio } from "./audio"

import MediaWorker from "./worker?worker"
// import WebWorker from 'web-worker:./Worker.ts';
import MediaWorker from "web-worker:./worker/index.ts"

import { RingShared } from "../common/ring"
import { Root, isAudioTrack } from "../media/catalog"
import { GroupHeader } from "../transport/objects"
Expand All @@ -26,8 +26,7 @@ export default class Backend {

constructor(config: PlayerConfig) {
// TODO does this block the main thread? If so, make this async
// @ts-expect-error: The Vite typing is wrong https://github.com/vitejs/vite/blob/22bd67d70a1390daae19ca33d7de162140d533d6/packages/vite/client.d.ts#L182
this.#worker = new MediaWorker({ format: "es" })
this.#worker = new MediaWorker()
this.#worker.addEventListener("message", this.on.bind(this))

let sampleRate: number | undefined
Expand Down
2 changes: 1 addition & 1 deletion lib/playback/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export interface PlayerConfig {
}

// This class must be created on the main thread due to AudioContext.
export class Player {
export default class Player {
#backend: Backend

// A periodically updated timeline
Expand Down
67 changes: 67 additions & 0 deletions lib/rollup.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/* eslint-disable @typescript-eslint/no-var-requires */
"use strict"
const resolve = require("@rollup/plugin-node-resolve")
const commonjs = require("@rollup/plugin-commonjs")
const typescript = require("@rollup/plugin-typescript")
const workerLoader = require("rollup-plugin-web-worker-loader")
const babel = require("@rollup/plugin-babel")
const terser = require("@rollup/plugin-terser")
const sourceMaps = require("rollup-plugin-sourcemaps")
const pkg = require("./package.json")

const config = []

config.push({
input: pkg.entry,
output: {
file: pkg.iife,
format: "iife",
name: "moqplayer",
sourcemap: true,
},
plugins: [
resolve(),
commonjs({
include: [/node_modules/, /src/],
transformMixedEsModules: true,
}),
workerLoader({ preserveSource: true }),
typescript({
typescript: require("typescript"),
}),
sourceMaps(),
babel({
babelHelpers: "bundled",
presets: ["@babel/preset-env", "@babel/preset-typescript"],
exclude: "./node_modules/*",
}),
terser(),
],
})

config.push({
input: pkg.entry,
output: {
file: pkg.module,
format: "esm",
sourcemap: true,
},
external: [],
plugins: [
resolve(),
commonjs(),
workerLoader({ preserveSource: true }),
typescript({
typescript: require("typescript"),
}),
sourceMaps(),
babel({
babelHelpers: "bundled",
presets: ["@babel/preset-env", "@babel/preset-typescript"],
exclude: "./node_modules/*",
}),
terser(),
],
})

module.exports = config
2 changes: 1 addition & 1 deletion lib/transport/control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ export class Decoder {

private async msg(): Promise<Msg> {
const t = await this.r.u53()
switch (t) {
switch (t as Id) {
case Id.Subscribe:
return Msg.Subscribe
case Id.SubscribeOk:
Expand Down
46 changes: 11 additions & 35 deletions lib/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,42 +1,18 @@
{
"files": [], // don't build anything with these settings.
"compilerOptions": {
"target": "es2022",
"module": "es2022",
"sourceMap": true,
"moduleResolution": "node",
"rootDir": ".",
"module": "es2022",
"target": "es2022",
"lib": ["es2022", "dom", "dom.iterable"],
"outDir": "./dist",
"declaration": true,
"strict": true,
"composite": true,
"declarationMap": true,
"sourceMap": true,
"isolatedModules": true,
"types": [], // Don't automatically import any @types modules.
"lib": ["es2022", "dom"],
"typeRoots": ["./types", "../node_modules/@types"]
"allowJs": false,
"allowSyntheticDefaultImports": true,
"downlevelIteration": true,
"removeComments": false,
"isolatedModules": false,
"noEmit": false
},
"references": [
{
"path": "./common"
},
{
"path": "./playback"
},
{
"path": "./playback/worklet"
},
{
"path": "./contribute"
},
{
"path": "./transport"
},
{
"path": "./media"
}
],
"paths": {
"@/*": ["*"]
}
"exclude": ["node_modules"]
}
9 changes: 9 additions & 0 deletions lib/types/workers.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
declare module "web-worker:*" {
const WorkerFactory: new () => Worker
export default WorkerFactory
}

declare module "audio-worklet:*" {
const value: any
export default value
}
Loading

0 comments on commit 03d6329

Please sign in to comment.