live-dragon-stage
v1.10.5
Published
ray-streaming launcher for doulong
Downloads
1
Readme
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)