nvidia stream的一些资料

nvidia stream的一些资料

1. 简要的信息

入口app的设置

在HKLM\Software\Nvidia Corporation\NvStream的AppCollectorEntries项目下,此项目指示了一个目录,此目录里放的是指向入口app的快捷方式。

注册表位置如下

file

该文件夹如下

file

打开gamestream

修改注册表

HKLM\Software\Nvidia Corporation\NvStream的EnableStreaming -〉1

从UI上打开需要在locate session上操作,远控时很不方便。

配对

配对实际是一个服务端和客户端相互交换证书的过程。客户端首先会向服务端发起https请求,并附上自己的证书。服务端会检测客户端的证书是否在受信任的个体列表中。在服务端,证书通过api CryptUIWizImport() 存放于windows中。具体的,在注册表[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SystemCertificates\TrustedPeople\Certificates\处。

在新机器上导入此处注册表即可完成服务端的配对。

同时,客户端也需要保存服务端证书。服务端的证书在https请求时得到,此时客户端会比较此证书是否在自身的受信任个体中。可在客户端中去掉此处逻辑。

在官方不支持的显卡上强制开启gamestream

这个不支持是指geforce exprience主动派出的一些非消费级显卡(例如telsa系列),显卡本身具有此功能,但nvidia出于商业考虑不愿在这些显卡上开启game stream.

在此情况下,可以通过修改gfe的本地逻辑,强制打开gamestream。

更新: 可以绕过gfe,直接启动核心的nvstreamer进行串流。详见简化GFE串流交互

GFE串流交互

分析moonlight客户端,可以知道gfe开启串流的官方交互流程。

  1. 解锁local session下的windows。串流的相关服务仅在windows解锁之后才会开始,并当windows锁定时自动停止。
  2. 向gfe的http服务或者https服务发送请求。请求中携带客户端uuid,服务端返回服务端的基本信息:服务端uuid、gfe版本、支持的视频模式、支持的编码器、是否配对等等。如果客户端当前保存有服务端的证书,则使用http,否则使用https。http请求返回的pairstate永远为0,即若无证书则必须进行配对。后续的一些操作(例如开启串流)必须使用https接口。

请求样例:http://119.29.99.43:51056/serverinfo?uniqueid=0123456789ABCDEF&uuid=febaf73bc8604bf8b684b2f10ef4b325

返回样例:

"<?xml version=\"1.0\" encoding=\"UTF-16\"?><root protocol_version=\"0.1\" query=\"serverinfo\" status_code=\"200\" status_message=\"OK\"><AuthenticationType>1</AuthenticationType><ConnectionState></ConnectionState><CurrentClient>0</CurrentClient><GfeVersion>3.21.0.36</GfeVersion><GsVersion>gs_04_24_29379715</GsVersion><HttpsPort>47984</HttpsPort><LocalIP>192.168.21.44</LocalIP><LocalIPs><Address>192.168.21.44</Address></LocalIPs><LoginState>1</LoginState><MaxLumaPixelsH264>1721324928</MaxLumaPixelsH264><MaxLumaPixelsHEVC>1869449984</MaxLumaPixelsHEVC><Mode>0</Mode><PairStatus>0</PairStatus><ServerCapability>3895</ServerCapability><ServerCodecModeSupport>3843</ServerCodecModeSupport><ServerColorSpaceSupport>2</ServerColorSpaceSupport><SupportedDisplayMode><DisplayMode><Height>2160</Height><RefreshRate>30</RefreshRate><Width>3840</Width></DisplayMode><DisplayMode><Height>1080</Height><RefreshRate>60</RefreshRate><Width>1920</Width></DisplayMode><DisplayMode><Height>1080</Height><RefreshRate>30</RefreshRate><Width>1920</Width></DisplayMode><DisplayMode><Height>720</Height><RefreshRate>60</RefreshRate><Width>1280</Width></DisplayMode><DisplayMode><Height>720</Height><RefreshRate>30</RefreshRate><Width>1280</Width></DisplayMode></SupportedDisplayMode><accountId></accountId><appversion>7.1.424.0</appversion><currentgame>0</currentgame><gamelistid>05aa7dba662bff5a1b18efccf6778114</gamelistid><gputype>GeForce RTX 2080 Ti</gputype><hostname>DESKTOP-78RKJ3U</hostname><mac>18:16:24:01:00:54</mac><numofapps>0</numofapps><resyncSuccessful>0</resyncSuccessful><state>MJOLNIR_STATE_SERVER_AVAILABLE</state><uniqueid>08f7e250-d661-4881-8123-0b3ee31b7557</uniqueid></root>
  1. 如果没有配对,进行如下的配对流程,否则跳转到4
  2. 配对:细节暂未分析,但目标是服务端和客户端相互存储对方证书。
  3. 使用https接口查询远程主机的串流目标列表。串流目标指远程主机上面的程序,后续串流会把该程序的画面传回来。指定串流目标为c:\windows\system32\mstsc.exe的含义为串流整个桌面。

请求示例:https://119.29.99.43:51055/applist?uniqueid=0123456789ABCDEF&uuid=747f0bc4fda2403896ba70dba5776d40

返回样例:

"<?xml version=\"1.0\" encoding=\"UTF-16\"?><root protocol_version=\"0.1\" query=\"applist\" status_code=\"200\" status_message=\"OK\"><App><AppInstallPath>C:\\steam\\steamapps\\common\\Counter-Strike Global Offensive\\</AppInstallPath><AppTitle>Counter Strike: Global Offensive</AppTitle><CmsId>7315111</CmsId><Distributor></Distributor><ID>491324143</ID><IsAppCollectorGame>0</IsAppCollectorGame><IsHdrSupported>0</IsHdrSupported><MaxControllersForSingleSession>1</MaxControllersForSingleSession><ShortName>counter_strike_global_offensive</ShortName><SupportedSOPS></SupportedSOPS><UniqueId>0</UniqueId><simulateControllers>0</simulateControllers></App><App><AppInstallPath></AppInstallPath><AppTitle>mstsc</AppTitle><CmsId></CmsId><Distributor></Distributor><ID>8417296</ID><IsAppCollectorGame>1</IsAppCollectorGame><IsHdrSupported>0</IsHdrSupported><MaxControllersForSingleSession>1</MaxControllersForSingleSession><ShortName>mstsc</ShortName><SupportedSOPS></SupportedSOPS><UniqueId>0</UniqueId><simulateControllers>0</simulateControllers></App></root>"
  1. 找到串流目标的id后,请求主机打开(或者继续)这个程序。在该请求中会指定后续controlchannel使用的ase密钥和iv,密钥和iv都是客户端动态随机生成的。在该请求发送到服务端后,服务端会启动NvStreamer.exe子进程,该进程是一个rtsp server。返回的数据中也包含了这个rtsp server的地址。

请求示例:https://119.29.99.43:51055/resume?uniqueid=0123456789ABCDEF&uuid=9b1945f4fb3a4a87aa8169f03f49209e&rikey=064bc9466164c6ee254ebcb5fd3bb6bc&rikeyid=425268044&surroundAudioInfo=196610

返回样例

"<?xml version=\"1.0\" encoding=\"UTF-16\"?><root protocol_version=\"0.1\" query=\"resume\" status_code=\"200\" status_message=\"OK\"><DisplayHeight>1080</DisplayHeight><DisplayWidth>1920</DisplayWidth><HdrMode>0</HdrMode><RefreshRate>60</RefreshRate><resume>1</resume><rikey>ok</rikey><sessionUrl0>rtsp://192.168.21.44:48010</sessionUrl0></root>"
  1. 客户端对rtsp server进行连接,获取串流画面。客户端同时会连接controlchannel(47999-udp,监听者是nvstreamer.exe),该通道用于传输客户端的鼠标键盘操作事件。服务端的nvstreamer自身没有能力模拟这些输入,它收到这些事件后通过Nv通用的MessageBus向其他进程传递此消息,由其他进程进行按键模拟。

串流交互简化

按照对交互流程的分析,直接拉起NvStreamer.exe作为rtsp服务即可。音频和画面工作正常,控制事件需要自己实现。

通过如下命令行启动NvStreamer.exe。注意工作目录必须在C:\Program Files\NVIDIA Corporation\NvContainer\

"C:\Program Files\NVIDIA Corporation\NvStreamSrv\nvstreamer.exe" --shield --streaming-pid 0 --log-file "D:\NvStreamerLog\NvStreamerCurrent.log" --log-level "debug" --show-pii-in-logs --ri-enc-key 00000000000000000000000000000000 --ri-enc-key-id 0

新机器,新版本

在新机器(rtx3060)上,旧的442.59驱动不支持了,要安装新驱动。在新驱动下旧的gfe中的串流功能也用不了了,所以不得不把gfe更新至3.25.1.27

更新之后远控的接口变了,要做如下改动。

  1. nvstreamer的命令行变成如下
"C:\Program Files\NVIDIA Corporation\NvStreamSrv\nvstreamer.exe" --shield --streaming-pid 0 --log-file "D:\NvStreamerLog\NvStreamerCurrent.log" --log-level "debug" --show-pii-in-logs --ri-enc-key 00000000000000000000000000000000 --ri-enc-key-id 0
  1. 要对nvstreamer进程中的streamservershared.dll 做 patch

file

原因是rtsp握手时control protocol和服务端的预期不一样,预期是9。但旧的客户端给的是1。可以从日志看出来:

file

因为实际上按键模拟已经被我接管了,所以这个control protocol实际上是用不到的,所以给服务端提供一个合理的数据让它能跑通即可。

2. 杂项

一些设置可以在注册表的下图位置找到

appcollectionentries似乎是用于提示的,修改这个值也不会改变它实际存放入口app信息的位置。此位置固定是c:\users\xxx\appdata\local\nvidia corporation\shield apps

moonlight发送控制包(键盘/鼠标事件)时,会经过aes加密。密钥和iv是每次动态生成的,在launchapp阶段告知服务器。

file

file

在nvstreamer的命令行中可指示这两个参数

--ri-enc-key 00000000000000000000000000000000 --ri-enc-key-id 0

可惜,nvstreamer是通过messagebus向nvcontainer的某个插件发送消息完成模拟输入的。单独只有nvstreamer的时候无法模拟。

几个端口的含义

file

nvstream工作时的端口情况

file

nvstreamer的参数

file

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注