live-dragon-stage
TypeScript icon, indicating that this package has built-in type declarations

1.10.5 • Public • Published

Doulong RayStreaming Launcher

RayStreaming launcher

Launcher for Windows streaming

Quick start

instantiation parameter

type Phase =
  | 'initial'
  | 'signaling-connected'
  | 'node-ready'
  | 'end-candidate'
  | 'peer-connection-connected'
  | 'bandwidth-detect'
  | 'data-channel-open' // able to interact
  | 'loaded-metadata' // video play

interface Options {
  themeColor: string // hex color for widgets
  minBitrate: number
  maxBitrate: number
  startBitrate: number
  iceTransportPolicy: RTCIceTransportPolicy
  enableClipboard: boolean
  enableControlPanel: boolean
  autorunRivatuner: boolean // start statistics as default
  orientationLock: boolean // no longer auto-rotate the streaming orientation to fit the container size
  disablePointerManager: boolean // disable sync cursor style with the remote node
  disablePointerLock: boolean // no longer call requestPointerLock when cursor style is null
  disableFileTransfer: boolean
  disableWinTouch: boolean
  onError: (reason: string) => void
  onRotate: (result: boolean) => void
  onPhaseChange: (phase: Phase, deltaTime: number) => void
  onNetworkChange: (reason: string) => void // switch network or weak network
}

simple use

import { Launcher, screenfull } from 'live-dragon'

// NOTE: token, address and iceServers were provided by Doulong console
const token = 'xxxxxxxxxxxxxxxxxxxxxxxx'
const address = 'wss://xxx.xxx.xxx.xxx:xxxx'
const iceServers = [
  {
    urls: 'turn:xxx.xxx.xxx.xxx',
    username: 'xxxxxx',
    credential: 'xxxxxx',
  },
  {
    urls: 'stun:xxx.xxx.xxx.xxx',
    username: 'xxxxxx',
    credential: 'xxxxx',
  },
]

const container = document.createElement('div')
container.style.width = '1280px'
container.style.height = '720px'
container.style.margin = 'auto'
document.body.appendChild(container)

const launcher = new Launcher(`${address}/clientWebsocket/${token}`, iceServers, container, options)

/* NOTE: fullscreen need user activation gesture
 * @see https://html.spec.whatwg.org/multipage/interaction.html#user-activation-processing-model
 */
someTriggerElement.addEventListener('click', () => screenfull.request(container))

Adjust bandwidth

// ...
launcher.changeBandwidth(
  8000, // start bitrate kbps
  10000, // max bitrate kbps
  5000, // min bitrate kbps
)

Statistics

// ...
launcher.toggleStatistics()
window.setInterval(() => {
  const { fps, bitrate, packetLossRate, latency, averageJitterBufferDelay } = launcher.report()
  console.log(`
    FPS: ${fps}
    biterate: ${bitrate}kbps
    latency: ${latency}ms
    averageJitterBufferDelay: ${averageJitterBufferDelay}ms
    packetLossRate: ${(packetLossRate * 100).toFixed(3)}%
  `)
}, 1000)

Dashboard

// ...
launcher.showDashboard()
launcher.hideDashboard()
// NOTE: export statistics and log data
launcher.exportLog()

Screenshot

// ...
launcher.screenshot()
// NOTE: offer onByteReceived callback
launcher.screenshot(function onByteReceived(byteLength) {
  // do something
})

Handle phase change

new Launcher(signaling, iceServers, container, {
  onPhaseChange: (phase, deltaTime) => {
    console.log(`${deltaTime}ms cost from initial to this phase: ${phase}`)
  },
})

Display control panel

new Launcher(signaling, iceServers, container, {
  enableControlPanel: true,
})

Change codec options

launcher.changeCodecOptions({
  bitrate: 8000,
  framerate: 60,
  gopLength: 250,
})

Change encode resolution

// ...
// change encode resolution to WXGA
launcher.changeEncodeResolution(1280, 768)

Microphone

// start capture audio to node
launcher.openMicrophone()
// stop
launcher.closeMicrophone()

On-Screen controls

config shape

type MouseScheme =
  | 'left-mouse-button'
  | 'right-mouse-button'
  | 'middle-mouse-button'
  | 'forward-scroll-wheel'
  | 'backward-scroll-wheel'
  | 'scroll-wheel'
type JoyStickScheme = 'wasd' | 'direction' | 'look' | 'd-pad'
enum ControlType {
  Button = 0,
  JoyStick = 10,
  Combine = 20,
  Mouse = 30,
  Mobile = 40,
}
type BaseControlType = {
  type: ControlType
  opacity: number
  aspectRatio: number
  xPercent: number
  yPercent: number
  widthPercent: number
  heightPercent: number
  showName: string
  srcList: string[]
  anchor: 'screen' | 'graphics'
}
type ButtonControl = BaseControlType & {
  codes: number
  type: ControlType.Button
  schemeKeys: string
}
type JoyStickControl = BaseControlType & {
  codes: null
  type: ControlType.JoyStick
  schemeKeys: JoyStickScheme
}
type MouseControl = BaseControlType & {
  codes: null
  type: ControlType.Mouse
  schemeKeys: MouseScheme
}
type ControlConfig = MouseControl | JoyStickControl | ButtonControl

use example

configList can provide by controller manager or customize by above config shape

// ...
const id = launcher.createOnScreenControlsProfile('specify-name', configList)
launcher.showOnScreenControlsByProfileId(id)

default joy-stick

// ...
launcher.showJoyStick()
launcher.hideJoyStick()

default touch keyboard

// ...
launcher.showKeyboard()
launcher.hideKeyboard()

Trackpad

only use on touch device

// ...
// enable trackpad with direct mode
launcher.enableTrackpad('direct')
// enable trackpad with relative mode
launcher.enableTrackpad('relative')
launcher.disableTrackpad()

Wake on input method editor

// ...
launcher.wakeOnIME()

Magnifier

// ...
launcher.showMagnifier()
launcher.hideMagnifier()
// resize magnifier dimension
launcher.updateMagnifierSize(480, 240)

Change resolution

// ...
// change resolution to WXGA
launcher.changeResolution(1280, 768)

Launcher for Android streaming

instantiation parameter

interface Options {
  minBitrate: number
  maxBitrate: number
  startBitrate: number
  iceTransportPolicy: RTCIceTransportPolicy
  enableClipboard: boolean
  enableControlPanel: boolean
  autorunRivatuner: boolean
  orientationLock: boolean
  enableNavigation: boolean // show navigation bar in control panel
  onError: (reason: string) => void
  onRotate: (result: boolean) => void
  onPhaseChange: (phase: Phase, deltaTime: number) => void
}

simple use

import { MobileLauncher } from 'live-dragon'

const mobileLauncher = new MobileLauncher(
  `${address}/signaling/client/${token}`,
  iceServers,
  container,
  options,
)
// NOTE: send KEYCODE_3 down & up
mobileLauncher.sendMobileAction(3, 0)
mobileLauncher.sendMobileAction(3, 1)

Synchronizer

import { Synchronizer } from 'live-dragon'

const config = [
  {
    address: 'wss://xxx.xxx.xxx.xxx:xxxx',
    token: 'xxxxxxxxxxxxxxxxxxxxxxxx',
    iceServers: [
      { urls: 'turn:xxx.xxx.xxx.xxx:xxxx', username: 'xxxxxx', credential: 'xxxxxx' },
      { urls: 'stun:xxx.xxx.xxx.xxx:xxxx', username: 'xxxxxx', credential: 'xxxxxx' },
    ],
  },
  {
    address: 'wss://xxx.xxx.xxx.xxx:xxxx',
    token: 'xxxxxxxxxxxxxxxxxxxxxxxx',
    iceServers: [
      { urls: 'turn:xxx.xxx.xxx.xxx:xxxx', username: 'xxxxxx', credential: 'xxxxxx' },
      { urls: 'stun:xxx.xxx.xxx.xxx:xxxx', username: 'xxxxxx', credential: 'xxxxxx' },
    ],
  },
]

const synchronizer = new Synchronizer(document.body)
const ids = config.map(({ address, token, iceServers }) =>
  synchronizer.createInstance(`${address}/clientWebsocket/${token}`, iceServers),
)
// NOTE: strat/stop mirror mouse and keyboard event
synchronizer.link(id)
synchronizer.unlink(id)
// NOTE: destroy player and release listener
synchronizer.remove(id)
// NOTE: main node have correct pointer state
synchronizer.setMainNode(id)

Readme

Keywords

Package Sidebar

Install

npm i live-dragon-stage

Weekly Downloads

2

Version

1.10.5

License

MIT

Unpacked Size

485 kB

Total Files

22

Last publish

Collaborators

  • huyurun
  • kitsch