Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Richard's webrtc playground #11

Draft
wants to merge 45 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
5ecfbc4
wip: Asset manager
eol-account Dec 17, 2020
c88944a
bodge: Run commands on startup
eol-account Dec 17, 2020
bbf6302
feat: Accept close signal (Ctrl+D)
eol-account Dec 17, 2020
365b545
fix: Check for existence of media folder
eol-account Dec 17, 2020
fb8ccb3
bodge: Use git versions of everything
eol-account Dec 17, 2020
dfbf75c
chore: Add buildstart command
eol-account Dec 17, 2020
bb182e6
chore: Set UV_THREADPOOL_SIZE on start
eol-account Dec 17, 2020
7cbb03e
chore: Update yarn.lock
eol-account Dec 17, 2020
d36c7d2
fix: Use published version of redioactive
eol-account Dec 17, 2020
c077cc7
feat: WIP on webRTC consumer
jstarpl Dec 18, 2020
b902966
chore: some more WIP
jstarpl Dec 18, 2020
7111af8
chore: make the connection manager API TypeScript
jstarpl Dec 18, 2020
bb91308
Merge remote-tracking branch 'jstarpl/feat/webrtc-consumer' into test…
eol-account Dec 18, 2020
74de37c
feat: working? WebRTC consumer?
jstarpl Dec 18, 2020
1b8105f
Merge remote-tracking branch 'jstarpl/feat/webrtc-consumer' into test…
eol-account Dec 18, 2020
d88af6f
wip: WebRTC
eol-account Dec 18, 2020
0c7812d
Merge remote-tracking branch 'jstarpl/feat/webrtc-consumer' into test…
eol-account Dec 18, 2020
8096238
wip: WebRTC
eol-account Dec 18, 2020
4175296
fix: Types
eol-account Dec 18, 2020
a06740d
fix: Device index
eol-account Dec 18, 2020
f1bd91c
fix: Types
eol-account Dec 18, 2020
653372b
fix: Device index
eol-account Dec 18, 2020
e7d6c1e
feat: webrtc consumers have an id that a peer must provide to connect…
Julusian Dec 18, 2020
d609259
fix: rename api endpoints
Julusian Dec 18, 2020
5f0140d
wip: Some WebRTC audio
eol-account Dec 18, 2020
b3e3173
chore: refactor player js
Julusian Dec 18, 2020
659c20a
Merge remote-tracking branch 'Julian/test/cloud' into test/webrtc
eol-account Dec 18, 2020
600b89e
Merge remote-tracking branch 'origin/master' into test/webrtc
eol-account Feb 18, 2021
29bc992
chore: Richard's webrtc playground
sparkpunkd Mar 31, 2021
e04f5d0
chore: update webrtc producer after merge
sparkpunkd Mar 31, 2021
6da6f84
chore: getting up and running
sparkpunkd Apr 5, 2021
7dee8c6
chore: back to video playing
sparkpunkd Apr 6, 2021
b552131
chore: re-wiring negociation to match webrtc basic example
sparkpunkd Apr 8, 2021
b5b5ecb
chore: re-wiring negociation to match webrtc basic example
sparkpunkd Apr 8, 2021
ae4340d
chore: commit due to odd merge behaviour
sparkpunkd Apr 8, 2021
762c281
fix: audio streaming working - though some sync/reliability issues
sparkpunkd Apr 8, 2021
e35cfc7
chore: experimenting with data channels
sparkpunkd Apr 8, 2021
96ae021
chore: basic demo buttons
sparkpunkd Apr 9, 2021
5c895bf
chore: using phaneron's yuv420p GPU converter rather than libyuvs CPU…
sparkpunkd Apr 9, 2021
087f9ce
chore: added back in audio fix that got lost somewhere
sparkpunkd Apr 9, 2021
38d7452
chore: stream pacing
sparkpunkd Apr 9, 2021
3a3414a
chore: plumbing channel through WebRTC consumer
sparkpunkd Apr 9, 2021
cbc8af1
Merge branch 'feat/webrtc' of https://github.com/Streampunk/phaneron …
sparkpunkd Apr 9, 2021
a55f340
chore: scale and rotation sliders
sparkpunkd Apr 9, 2021
c9b3765
chore: working towards video inputs
sparkpunkd Apr 20, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,9 @@ dist

# TernJS port file
.tern-port

# Media folder
media/

# Startup commands
startupAMCPCommands
16 changes: 14 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,36 @@
"license": "GPL-3.0",
"private": false,
"scripts": {
"buildstart": "yarn build && yarn start",
"build": "trash dist && yarn build:main",
"build:main": "tsc -p tsconfig.json",
"lint": "eslint . --ext .ts",
"lint:fix": "yarn lint --fix",
"start": "node dist/index.js"
"start": "node dist/index.js",
"build-start": "yarn build && yarn start"
},
"dependencies": {
"@koa/cors": "3",
"@types/koa-bodyparser": "^4.3.0",
"@types/koa-route": "^3.2.4",
"@types/uuid": "^8.3.0",
"@types/webrtc": "^0.0.26",
"beamcoder": "^0.6.11",
"koa": "^2.13.0",
"koa-bodyparser": "^4.3.0",
"koa-route": "^3.2.0",
"koa-static": "^5.0.0",
"macadam": "^2.0.14",
"naudiodon": "^2.3.4",
"nodencl": "^1.3.1",
"redioactive": "0.0.16",
"ts-osc": "^0.3.1"
"ts-osc": "^0.3.1",
"uuid": "^8.3.2",
"wrtc": "^0.4.7"
},
"devDependencies": {
"@types/koa": "2.11.6",
"@types/koa-static": "^4.0.1",
"@types/koa__cors": "3.0.2",
"@types/node": "^14.14.28",
"@typescript-eslint/eslint-plugin": "^4.15.1",
Expand Down
6 changes: 5 additions & 1 deletion src/AMCP/basicCmds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { Channel } from '../channel'
import { ConsumerRegistry } from '../consumer/consumer'
import { ClJobs } from '../clJobQueue'
import { ConfigParams } from '../config'
import { assetManager } from '../assets/assetManager'

export class BasicCmds implements CmdList {
private readonly consumerRegistry: ConsumerRegistry
Expand Down Expand Up @@ -104,8 +105,10 @@ export class BasicCmds implements CmdList {
if (params.find((param, i) => { curParam = i; return param === 'SEEK' }) !== undefined)
seek = +params[curParam + 1]

const url = await assetManager.getAsset(clip)

const loadParams: LoadParams = {
url: clip,
url: url,
layer: chanLay.layer,
channel: chanNum,
loop: loop,
Expand Down Expand Up @@ -224,6 +227,7 @@ export class BasicCmds implements CmdList {

try {
const consumer = this.consumerRegistry.createConsumer(
channel,
chanLay.channel,
consumerIndex,
this.parseParams(params),
Expand Down
28 changes: 28 additions & 0 deletions src/assets/assetManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import fs from 'fs'
import path from 'path'

const MEDIA_DIR = '../media/dpp/'

class AssetManager {
public getAsset(clip: string): Promise<string> {
const files = fs.existsSync(MEDIA_DIR) ? fs.readdirSync(MEDIA_DIR) : []
console.log("FILES:", files)
if (clip.match(/^(?!file).*:\/\//i)) {
return Promise.resolve(clip)
}

const exact_match = files.find((f) => f === clip)
if (exact_match) {
return Promise.resolve(path.join(MEDIA_DIR, exact_match))
}

const inexact_match = files.find((f) => f.toUpperCase() === clip.toUpperCase())
if (inexact_match) {
return Promise.resolve(path.join(MEDIA_DIR, inexact_match))
}

return Promise.reject(`Could not find clip ${clip}`)
}
}

export const assetManager = new AssetManager()
1 change: 1 addition & 0 deletions src/channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export class Channel {
this.clJobs = clJobs
this.combiner = new Combiner(this.clContext, chanID, this.consumerConfig.format, this.clJobs)
this.consumers = this.consumerRegistry.createConsumers(
this,
chanNum,
chanID,
this.consumerConfig,
Expand Down
8 changes: 7 additions & 1 deletion src/consumer/consumer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { Frame } from 'beamcoder'
import { Channel } from '../channel'
import { ConfigParams, VideoFormat, DeviceConfig, ConsumerConfig } from '../config'
import { ClJobs } from '../clJobQueue'
import { WebRTCConsumerFactory } from './webrtcConsumer'

export interface Consumer {
initialise(): Promise<void>
Expand All @@ -35,6 +36,7 @@ export interface Consumer {

export interface ConsumerFactory<T extends Consumer> {
createConsumer(
channel: Channel,
chanID: string,
params: ConfigParams,
format: VideoFormat,
Expand All @@ -55,12 +57,14 @@ export class ConsumerRegistry {
this.consumerFactories.set('decklink', new MacadamConsumerFactory(clContext))
this.consumerFactories.set('screen', new ScreenConsumerFactory(clContext))
this.consumerFactories.set('ffmpeg', new FFmpegConsumerFactory(clContext))
this.consumerFactories.set('webrtc', new WebRTCConsumerFactory(clContext))
this.consumers = new Map()
this.chanIDs = new Map()
this.formats = new Map()
}

createConsumer(
channel: Channel,
chanNum: number,
consumerIndex: number,
params: ConfigParams,
Expand All @@ -83,6 +87,7 @@ export class ConsumerRegistry {
if (!format) throw new Error(`channel format not registered`)

const consumer = factory.createConsumer(
channel,
chanID,
params,
format,
Expand Down Expand Up @@ -115,6 +120,7 @@ export class ConsumerRegistry {
}

createConsumers(
channel: Channel,
chanNum: number,
chanID: string,
config: ConsumerConfig,
Expand All @@ -124,7 +130,7 @@ export class ConsumerRegistry {
this.formats.set(chanNum, config.format)

return config.devices.map((device) =>
this.createConsumer(chanNum, this.consumerIndex++, {}, device, clJobs)
this.createConsumer(channel, chanNum, this.consumerIndex++, {}, device, clJobs)
)
}
}
2 changes: 2 additions & 0 deletions src/consumer/ffmpegConsumer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { FromRGBA } from '../process/io'
import { Writer } from '../process/yuv422p8'
import { ConfigParams, VideoFormat, DeviceConfig } from '../config'
import { ClJobs } from '../clJobQueue'
import { Channel } from '../channel'

interface AudioBuffer {
buffer: Buffer
Expand Down Expand Up @@ -261,6 +262,7 @@ export class FFmpegConsumerFactory implements ConsumerFactory<FFmpegConsumer> {
}

createConsumer(
_channel: Channel,
chanID: string,
params: ConfigParams,
format: VideoFormat,
Expand Down
2 changes: 2 additions & 0 deletions src/consumer/macadamConsumer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { Writer } from '../process/v210'
import { Frame, Filterer, filterer } from 'beamcoder'
import { ConfigParams, VideoFormat, DeviceConfig } from '../config'
import { ClJobs } from '../clJobQueue'
import { Channel } from '../channel'

interface DecklinkConfig extends DeviceConfig {
keyDeviceIndex: number
Expand Down Expand Up @@ -296,6 +297,7 @@ export class MacadamConsumerFactory implements ConsumerFactory<MacadamConsumer>
}

createConsumer(
_channel: Channel,
chanID: string,
params: ConfigParams,
format: VideoFormat,
Expand Down
2 changes: 2 additions & 0 deletions src/consumer/screenConsumer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { FromRGBA } from '../process/io'
import { Writer } from '../process/rgba8'
import { ConfigParams, VideoFormat, DeviceConfig } from '../config'
import { ClJobs } from '../clJobQueue'
import { Channel } from '../channel'

interface AudioBuffer {
buffer: Buffer
Expand Down Expand Up @@ -237,6 +238,7 @@ export class ScreenConsumerFactory implements ConsumerFactory<ScreenConsumer> {
}

createConsumer(
_channel: Channel,
chanID: string,
params: ConfigParams,
format: VideoFormat,
Expand Down
126 changes: 126 additions & 0 deletions src/consumer/webrtcConsumer/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import Koa from 'koa'
import * as _ from 'koa-route'
import { ConsumerInfoExt } from './peerManager'
// import { RTCSessionDescriptionInit /* RTCPeerConnection, nonstandard as WebRTCNonstandard, MediaStream, MediaStreamTrack */ } from 'wrtc'
// const { RTCVideoSource /*, rgbaToI420, RTCAudioSource */ } = WebRTCNonstandard

export default function mountConnectionsApi(
kapp: Koa<Koa.DefaultState, Koa.DefaultContext>,
consumers: Map<string, ConsumerInfoExt>,
prefix: string = ''
) {
kapp.use(_.get(`${prefix}/streams`, (ctx) => {
ctx.body = JSON.stringify(Array.from(consumers.values()).map(c => ({ streamId: c.id, description: c.description})))
}))
kapp.use(_.get(`${prefix}/streams/:consumerId/connections`, (ctx, consumerId: string) => {
const consumer = consumers.get(consumerId)
if (!consumer) {
ctx.status = 404
return
}
ctx.body = consumer.connectionManager.getConnections()
}))
kapp.use(
_.post(`${prefix}/streams/:consumerId/connections`, async (ctx, consumerId: string) => {
try {
const consumer = consumers.get(consumerId)
if (!consumer) {
ctx.status = 404
return
}
let offer = ctx.request.body as RTCSessionDescription
// console.log('Received offer:', offer)
// const connection = new RTCPeerConnection({})
// await connection.setRemoteDescription(offer)
const connection = await consumer.connectionManager.createConnection(offer)
// console.log(connection.localDescription)
// ctx.body = connection
ctx.body = connection.localDescription
} catch (error) {
console.error(error)
ctx.status = 500
}
})
)
kapp.use(
_.delete(`${prefix}/streams/:consumerId/connections/:id`, (ctx, consumerId: string, id: string) => {
const consumer = consumers.get(consumerId)
if (!consumer) {
ctx.status = 404
return
}
const connection = consumer.connectionManager.getConnection(id)
if (!connection) {
ctx.status = 404
return
}
connection.close()
ctx.body = connection
})
)
kapp.use(
_.get(`${prefix}/streams/:consumerId/connections/:id`, (ctx, consumerId: string, id: string) => {
const consumer = consumers.get(consumerId)
if (!consumer) {
ctx.status = 404
return
}
const connection = consumer.connectionManager.getConnection(id)
if (!connection) {
ctx.status = 404
return
}
ctx.body = connection
})
)
kapp.use(
_.get(`${prefix}/streams/:consumerId/connections/:id/local-description`, (ctx, consumerId: string, id: string) => {
const consumer = consumers.get(consumerId)
if (!consumer) {
ctx.status = 404
return
}
const connection = consumer.connectionManager.getConnection(id)
if (!connection) {
ctx.status = 404
return
}
ctx.body = connection.toJSON().localDescription
})
)
kapp.use(
_.get(`${prefix}/streams/:consumerId/connections/:id/remote-description`, (ctx, consumerId: string, id: string) => {
const consumer = consumers.get(consumerId)
if (!consumer) {
ctx.status = 404
return
}
const connection = consumer.connectionManager.getConnection(id)
if (!connection) {
ctx.status = 404
return
}
ctx.body = connection.toJSON().remoteDescription
})
)
// kapp.use(
// _.post(`${prefix}/streams/:consumerId/connections/:id/remote-description`, async (ctx, consumerId: string, id: string) => {
// const consumer = consumers.get(consumerId)
// if (!consumer) {
// ctx.status = 404
// return
// }
// const connection = consumer.connectionManager.getConnection(id)
// if (!connection) {
// ctx.status = 404
// return
// }
// try {
// await connection.applyAnswer(ctx.request.body as RTCSessionDescriptionInit)
// ctx.body = connection.toJSON().remoteDescription
// } catch (error) {
// ctx.status = 400
// }
// })
//)
}
28 changes: 28 additions & 0 deletions src/consumer/webrtcConsumer/connections/connection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { EventEmitter } from 'events'

/**
* Lifted from: https://github.com/node-webrtc/node-webrtc-examples/
*/

export default class Connection extends EventEmitter {
id: string
state: 'open' | 'closed'

constructor(id: string, _options: {}) {
super()
this.id = id
this.state = 'open'
}

close() {
this.state = 'closed'
this.emit('closed')
}

toJSON() {
return {
id: this.id,
state: this.state
}
}
}
Loading