在HKLM\Software\Nvidia Corporation\NvStream的AppCollectorEntries项目下,此项目指示了一个目录,此目录里放的是指向入口app的快捷方式。
注册表位置如下
该文件夹如下
修改注册表
HKLM\Software\Nvidia Corporation\NvStream的EnableStreaming -〉1
从UI上打开需要在locate session上操作,远控时很不方便。
配对实际是一个服务端和客户端相互交换证书的过程。客户端首先会向服务端发起https请求,并附上自己的证书。服务端会检测客户端的证书是否在受信任的个体列表中。在服务端,证书通过api CryptUIWizImport() 存放于windows中。具体的,在注册表[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SystemCertificates\TrustedPeople\Certificates\
处。
在新机器上导入此处注册表即可完成服务端的配对。
同时,客户端也需要保存服务端证书。服务端的证书在https请求时得到,此时客户端会比较此证书是否在自身的受信任个体中。可在客户端中去掉此处逻辑。
这个不支持是指geforce exprience主动派出的一些非消费级显卡(例如telsa系列),显卡本身具有此功能,但nvidia出于商业考虑不愿在这些显卡上开启game stream.
在此情况下,可以通过修改gfe的本地逻辑,强制打开gamestream。
更新: 可以绕过gfe,直接启动核心的nvstreamer进行串流。详见简化GFE串流交互
分析moonlight客户端,可以知道gfe开启串流的官方交互流程。
请求样例: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>
请求示例: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>"
返回样例
"<?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>"
按照对交互流程的分析,直接拉起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
更新之后远控的接口变了,要做如下改动。
"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
原因是rtsp握手时control protocol和服务端的预期不一样,预期是9。但旧的客户端给的是1。可以从日志看出来:
因为实际上按键模拟已经被我接管了,所以这个control protocol实际上是用不到的,所以给服务端提供一个合理的数据让它能跑通即可。
一些设置可以在注册表的下图位置找到
appcollectionentries似乎是用于提示的,修改这个值也不会改变它实际存放入口app信息的位置。此位置固定是c:\users\xxx\appdata\local\nvidia corporation\shield apps
moonlight发送控制包(键盘/鼠标事件)时,会经过aes加密。密钥和iv是每次动态生成的,在launchapp阶段告知服务器。
在nvstreamer的命令行中可指示这两个参数
--ri-enc-key 00000000000000000000000000000000 --ri-enc-key-id 0
可惜,nvstreamer是通过messagebus向nvcontainer的某个插件发送消息完成模拟输入的。单独只有nvstreamer的时候无法模拟。
几个端口的含义
nvstream工作时的端口情况
nvstreamer的参数