mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-12 19:41:10 +00:00
Xbox Cloud Gaming: stream from the store and Games tab, native player with DroidDeck frame generation Stream Xbox games with Xbox Cloud Gaming (Game Pass) from DroidDeck, outside the Linux session. - Backend: `xodus-cli cloud-token` (tools/xbox/droiddeck-cloud-token.patch) gets the streaming tokens; they stay in memory. - Web player (default): the Greenlight player page (tools/xcloud-player, MIT) in a WebView, plus Microsoft's own xbox.com/play player. In-stream menu with screen effects (sharpen, colour, deband, FXAA, CRT, NTSC, Toon, fps cap), stream quality, performance overlay (level, layout, top right / top left) and rumble. - Native player (opt-in, Android 10+, Player engine: Native): Google's WebRTC (io.github.webrtc-sdk 125.6422.07, BSD) with the Greenlight protocol ported to Kotlin, in its own process (:xcloudnative) with its own instance of DroidDeck's compositor. Decoded frames reach the compositor as AHardwareBuffers (new stream mode, VK_ANDROID_external_memory_android_ hardware_buffer import), so DDFG 2x and LSFG 2x/3x/4x run on them. Live frame generation, frame-rate target (presets and a 10-165 fps slider, even pacing), zero-copy picture, small network buffer, fast decoder, instant controller input, overlay with engine and on-screen fps, background end, restart and web fallback. It takes the main process's tokens through XboxCloudTokenService; they are fetched ahead while a cloud game is shown. - The compositor requests the dma-buf import extensions only where the driver has them (the system driver has none). - Catalog: cloud availability, Game Pass plan CFQ7TTC0K6L8 counted, library filter All / Owned / Game Pass / Cloud, Stream and Add to Games on the store page, stream-only Games-tab entries (Stream + Download / Play + Stream). - Xbox games get VC++ 2015-2022 and the ARM64 runtime registry entries (vcredist2022_arm64, built in until the catalog has it) before each launch. - Controller focus reaches pickers opened from a game page (install location, uninstall); Add / Remove from Games keep the focus. Credits: Greenlight by UnknownSKL (Jim Kroon), MIT, player and protocol; Better xCloud for the resolution / OS mapping; MGamer404's Bannerlator #627 for the ARM64 runtime approach. Ported from the412banner's Bannerlator.
120 lines
3.9 KiB
TypeScript
120 lines
3.9 KiB
TypeScript
import { v4 as uuidv4 } from 'uuid'
|
|
|
|
import Channel from './channel'
|
|
import MessageHandler from './message/handler'
|
|
|
|
export default class MessageChannel extends Channel {
|
|
_handshakeCompleted = false
|
|
|
|
getChannelName() {
|
|
return 'message'
|
|
}
|
|
|
|
getChannelConfig() {
|
|
return {
|
|
protocol: 'messageV1',
|
|
ordered: true,
|
|
}
|
|
}
|
|
|
|
onOpen() {
|
|
console.log('[MessageChannel] Sending handshake...')
|
|
const handshake = JSON.stringify({
|
|
'type':'Handshake',
|
|
'version':'messageV1',
|
|
'id':'be0bfc6d-1e83-4c8a-90ed-fa8601c5a179',
|
|
'cv':'0',
|
|
})
|
|
this.send(handshake)
|
|
}
|
|
|
|
onMessage(event: MessageEvent<any>) {
|
|
const data = JSON.parse(event.data)
|
|
// console.log('[MessageChannel] received:', data)
|
|
|
|
switch(data.type){
|
|
case 'HandshakeAck':
|
|
console.log('[MessageChannel] Handshake completed')
|
|
this._handshakeCompleted = true
|
|
// Start control & input channels
|
|
this.getPlayer()._channels.control.sendAuthorization()
|
|
this.getPlayer()._channels.input.start()
|
|
this.sendConfig()
|
|
break
|
|
|
|
case 'TransactionStart':
|
|
case 'Message':
|
|
new MessageHandler(this, data)
|
|
break
|
|
|
|
default:
|
|
console.log('[MessageChannel] Unhandled message type:', data.type, data)
|
|
}
|
|
|
|
}
|
|
|
|
sendConfig(){
|
|
const systemUis = []
|
|
const systemVersion = [0, 2, 0]
|
|
const uiConfig = JSON.stringify(this.generateMessage('/streaming/systemUi/configuration', {
|
|
'version': systemVersion,
|
|
'systemUis': systemUis, // Xbox Windows app has [33], xCloud has [10,19,31,27,32,-41]
|
|
|
|
// 8 = unknown
|
|
// 10 = ShowVirtualKeyboard
|
|
// 13 = unknown
|
|
// 15 = unknown
|
|
// 19 = ShowMessageDialog
|
|
// 31 = ShowApplication
|
|
// 27 = ShowPurchase
|
|
// 32 = ShowTimerExtensions
|
|
// 33 = Xbox windows app, disables the nexus menu on xCloud (Alt nexus menu?)
|
|
// -44 = unknown
|
|
// 40 = unknown
|
|
// 41 = unknown
|
|
// -43 = unknown
|
|
|
|
// Possible options: Keyboard, PurchaseModal
|
|
}))
|
|
this.send(uiConfig)
|
|
|
|
const clientConfig = JSON.stringify(this.generateMessage('/streaming/properties/clientappinstallidchanged', { 'clientAppInstallId': 'c97d7ee0-73b2-4239-bf1d-9d805a338429' }))
|
|
this.send(clientConfig)
|
|
|
|
const orientationConfig = JSON.stringify(this.generateMessage('/streaming/characteristics/orientationchanged', { 'orientation': 0 }))
|
|
this.send(orientationConfig)
|
|
|
|
const touchConfig = JSON.stringify(this.generateMessage('/streaming/characteristics/touchinputenabledchanged', { 'touchInputEnabled': false }))
|
|
this.send(touchConfig)
|
|
|
|
const deviceConfig = JSON.stringify(this.generateMessage('/streaming/characteristics/clientdevicecapabilities', {}))
|
|
this.send(deviceConfig)
|
|
|
|
const dimensionsConfig = JSON.stringify(this.generateMessage('/streaming/characteristics/dimensionschanged', {
|
|
'horizontal': 1920,
|
|
'vertical': 1080,
|
|
'preferredWidth': 1920,
|
|
'preferredHeight': 1080,
|
|
'safeAreaLeft': 0,
|
|
'safeAreaTop': 0,
|
|
'safeAreaRight': 1920,
|
|
'safeAreaBottom': 1080,
|
|
'supportsCustomResolution':true,
|
|
}))
|
|
this.send(dimensionsConfig)
|
|
}
|
|
|
|
generateMessage(path, data) {
|
|
return {
|
|
'type': 'Message',
|
|
'content': JSON.stringify(data),
|
|
'id': uuidv4(),
|
|
'target': path,
|
|
'cv': '',
|
|
}
|
|
}
|
|
|
|
destroy() {
|
|
// console.log('DebugChannel destroy() called')
|
|
}
|
|
} |