投屏工夫详解,手机游戏直播方案相比较及Airp

投屏技术已经被大量用在身边的产品, 比如电视投屏, 投影仪, 视频会议产品中. 在iOS平台外的其他平台中都已经有非常成熟的标准和实现. 但在封闭的苹果iOS和Mac系统中, 苹果使用私有的Airplay协议进行多屏互动, 只开放给自己生态中的产品. 对此相关技术限制比较严格,甚至在iOS9中加上了更严格的加密算法, 直接导致很多投屏的产品不可用.

手游直播是直播行业中非常重要的一个垂直领域. 手游直播与其他移动直播相比主要是画面的来源不同, 手游直播其实是一种录屏技术. 游戏玩家在玩游戏的同时将画面内容实时地分享展示给其他观众, 在配上玩家自己的语音, 能够给观众带来比较有趣的观看体验. 手游直播与PC端游戏直播相比主要是设备的计算能力不同。
PC游戏直播有OBS等强大的第三方直播软件, 加上PC强劲有富余的计算能力, 使得PC游戏直播的门槛相对较低。
手游直播中由于Apple对个人隐私和安全性的重视, iOS手游直播相对于Android手游直播的难度又大了很多。

针对日益增长的汽车遥控无钥匙进入系统市场,飞思卡尔半导体近期推出了包含硬件和软件安全协议的整体解决方案。

iOS中的投屏方案:

一. 现有iOS录屏方案分析

为了解决iOS手游直播中视频数据采集的难题, 主要存在以下三种方案:

  1. 通过私有API获取系统的IOSurface
    这种方法效率比较高, 但是从iOS9 开始, 这个私有API的漏洞就被Apple堵上了, 新系统中无法使用;

  2. Airplay Screen Mirroring;

图片 1

Airplay Screen Mirroring

Airplay 是 Apple 提供的一种远程播放技术, 可以将iPhone、iPod touch、iPad及Mac上的音频,照片,ppt, 视频和系统界面镜像等内容传送到同一局域网中支持Airplay的设备(如:音箱、Apple TV)中播放. 其中Airplay Screen Mirroring 就是用于屏幕投影的功能,有iOS系统自身将屏幕内容进行采集压缩,通过网络投屏的其他设备上. 但 Airplay 是Apple的私有协议组, 并且为了安全考虑, 传输过程中音视频数据都是用Apple私有的Fairplay加密的, 因此要想获得这些数据, 必须破解Airplay的协议和并且破解Fairplay加密方式。
另外出于个人隐私保护和影视版权保护的考虑,Apple不允许录屏功能的软件上架 AppStore, 即使成功上架, 不久也会被强制下架。

  1. ReplayKit

图片 2

ReplayKit

Apple 注意到了广大用户对手游直播的呼声, 从iOS 9开始提供了ReplayKit, 给了用户主动对外分享屏幕内容的能力. 对与Replaykit, Apple在不断的增强, iOS9的时候还只能把特定App的画面录制成MP4的片段, 到iOS10 能够获取特定App的原始图像和声音, 到iOS11, 能够从系统级启动录制, 获得所有APP包括桌面的画面. 但是Replaykit是以APP扩展的方式存在的, 真正接受到画面, 进行压缩发送的部分, 并不是一个完整的应用程序, 而是一个在后台运行的扩展. Airplay则可以作为一个在后台运行的App, 相对来说, 完整App的稳定性和可控程度在现阶段可能要优于App扩展。

ReplayKit 的方案大家可以参考 KSYReplayKit 或者Apple 官方的文档。

汽车遥控无钥匙进入系统由发射端和集成于车身控制模块中的接收端组成。发射端将用户按键命令通过数据编码、加密和组帧后通过射频发射电路发射,而车内接收端则将接收到的信号通过射频解调、数据解码和帧解密后完成相应车门、车灯控制和报警等用户指令。系统框图如图1。

1, ReplayKit

二. KSYAirStreamer SDK

KSYAirStreamer SDK基于Airplay Screen Mirroring的录屏SDK,使用Airplay方案录屏, 其实就要求直播APP将自己伪装成一个Airplay的接收设备, 实现Airplay的协议,解密出Fairplay加密的数据, 再将数据转发出去。

图片 3

KSYAirStreamer

KSYAirStreamer_iOS 就提供了这样一个模拟接收设备的SDK, 开始录屏时iOS系统与SDK建立连接, SDK收到画面后, 编码发送到直播服务器. 其中编码和推流功能使用金山云直播SDK实现。

正常的Airplay镜像, 是当与手机在同一个局域网中有一台Apple TV时, 通过手机的控制中心(在屏幕下方边缘处上拨时出现), 可以看到候选的Airplay 设备, 选中对应的设备,即可开始镜像, 此时系统顶部的状态栏会变成蓝色, 并有AirPlay的logo。

使用KSYAirStreamer 进行录屏直播时, 则省去了用户手动选择设备的过程, 因为我们已经知道设备的名称, 可以直接主动的选择对应的设备. 这一步主要是通过调用私有API, 直接对控制中心进行操作实现的. 也是无法上AppStore的理由之一。

图片 4

iOS9中引入了ReplayKit, 让开发者有了一定的获取屏幕数据的能力. 并在iOS10和iOS11中继续扩展了ReplayKit的能力. 但还是有很大的限制, 比如在使用ReplayKit的api时只能录制当前应用的应用, 无法在应用进入后台之后继续录屏. 如果使用系统级别的屏幕录制,又无法获得每一帧的数据,只能获得最后录取的单个视频. 这样对第三方的开发有了非常大的限制.

2.1 KSYAirStreamKit

KSYAirStreamKit 将KSYAirTunesServer和金山云直播SDK中的音频采集和推流等组件 组装在一起共同实现了iOS录屏直播的功能。
需要录屏时, 构造一个KSYAirStreamKit的实例, 并通过kit 设置关于录屏和推流的一些配置,最后调用startService / stopService 方法, 即可启 / 停录屏。

    _kit = [[KSYAirStreamKit alloc] init];
    _kit.airCfg = [[KSYAirTunesConfig alloc] init];
    _kit.videoBitrate = 800; //kbps
    _kit.streamUrl = @"rtmp://xxx.xxx/live/stream";
    [_kit startService];
    ....
    [_kit stopService];

发射端:使用飞思卡尔低端8位MC9S08QG4/8(4K/8K flash)微控制器完成用户按键的数据编码、加密组帧,再通过SAW声表谐振器电路发射至UHF频段。

2, Airplay

2.2 Airplay镜像配置参数

启动镜像前, 需要根据实际情况, 设置airplay镜像的参数, 这一步和直播时设置摄像头采集的参数是类似的. 通过KSYAirTunesConfig类可以配置的参数内容如下:

参数名 类型 说明 默认值
airplayName NSString* Airplay接收设备的名称 ksyair
videoSize int 接收设备的尺寸, 指定的是MAX(宽,高) 960
framerate int 希望接收到iOS发送端的视频帧率 30
airTunesPort short 设置airtunes 服务的监听端口, 0 表示系统自动分配 0
airVideoPort short 设置视频数据的接收端口(带重试) 7100
macAddr NSData * 设备的mac地址, 默认随机生成,(长度为6字节) 随机

其中airplayName设定的字符串就是, 在控制中心中能够看到的设备的名称. 当同一个局域网需要有多个设备同时使用录屏SDK时, 建议这个名称加上设备相关的后缀, 避免冲突。

videoSize 和正常的分辨率设置不太一样, 只有一个数字. 竖屏时高度为videoSize, 宽度根据屏幕比例计算得到,横屏时则宽度为videoSize, 高度又系统自动计算. 实际测试发现, iOS 10以上的系统中,部分设备可能不支持低分辨率. 比如iPhone 6s等设备已经不支持720(416 * 720,或720 * 416)以下分辨率输出, 请按实际情况做分辨率调整. 设置这些分辨率容易导致系统异常, 可能需要重启手机才能恢复。

接收端:使用UHF射频接收芯片MC33596完成信号解调和数据曼彻斯特解码,再将数据传送到车身主控芯片(本参考设计选用了8位MC9S08DZ系列)进行数据解密和指令执行。

Airplay是苹果提供的一种多屏互动技术, 可以将音频照片,视频, 屏幕从iOS设备或者Mac电脑上投射到支持airplay接受的设备上,如Apple TV。这样可以将小屏映射到大屏,可以无线音乐,可以图片分享等等. 但是Airplay属于苹果私有协议方案,设备间的协商与传输过程都进行了加密处理,并不能用于其他平台中。我们已经完整的逆向了Airplay的全部协议栈,并破解了其加密方案,可以提供跨平台Airplay接收方案。这样可以方便实现跨平台的多屏共享。

2.3 推流参数设置

KSYAirStreamKit 中通过streamerBase实例来实现推流, 对应参数的配置请参考wiki中的描述。

加密协议:采用飞思卡尔研发的可变密钥安全协议。

同时,通过研究,我们也可以通过Airplay Mirroring技术,做到在iPhone上把自己的屏幕的内容投送给当前iPhone,在某些情况下这种airplay的破解却非常有用处,比如手游直播。这中投屏方案使用了iOS原生的投屏能力,并且是完全的软件方案,非常方便进行集成和使用。

2.4 声音采集

KSYAirStreamKit 中通过 KSYAUAudioCapture来实现的音频采集. 正常的Airplay镜像时, 其实是音频和画面同步被投影到AppleTV等设备上的. 但是当我们录屏时, 接收端也在同一个设备上, 这时候保持原有逻辑音频就会出现回环了. 因此实际上, 录屏时, 只有画面部分走Airplay协议发送, 而音频还是通过外放(Speaker)播放, 这样系统或者游戏等App的声音, 能和主播的声音一起, 通过 KSYAUAudioCapture一起采集进来, 观众听到的就是比较完整的场景声音了。

可变密钥安全协议是飞思卡尔专门为遥控类应用市场开发的安全传输协议。其特点:

下面将介绍Airplay Mirroring接收端的实现原理,并揭示相关协议交互过程。

2.5 状态变化和消息通知

整个录屏推流过程中, 有两个状态变化需要关注. 一个是来自数据源的KSYAirTunesServer的状态变化, 另一个是推流状态的变化。

采用128位密钥加密验证,增强了安全性。

Airplay Mirroring客户端的同屏交互过程,分为三个主要步骤:

2.5.1 Airplay镜像的状态变化

Airplay镜像 其实也是iOS系统和我们SDK通过网络进行连接交互的一个过程, 在连接阶段可能出错, 在连接成功后也可能受到网络变化等因素的影响断开连接. KSYAirTunesServer 通过 KSYAirDelegate代理协议来提供状态变化的通知, KSYAirStreamKit也转发了此代理协议.
didStartMirroring 和 didStopMirroring 方法负责通知Airplay镜像的启动和停止。
mirroringErrorDidOcccur 负责通知当前遇到的错误。

错误类型 说明 错误码值
KSYAirErrorCodePortConflict 端口冲突, 请检查airTunesPort/airVideoPort的配置 0
KSYAirErrorCodeNetworkDisconnection 网络未连接 1
KSYAirErrorCodeAirPlaySelectTimeout 连接AirPlay超时 2
KSYAirErrorCodeConnectBreak 连接断开(网络切换) 3
KSYAirErrorCodeOther 其他未知错误 4

密钥中的32位可变密钥部分随时间和按键而增加。

1, 设备广播与发现

2.5.2 推流状态变化通知

推流的状态变化和直播SDK中的内容一致, 请参考wiki
KSYAirStreamKit 中已经实现了基本的重连逻辑

即使在遥控距离外被多次按键操作之后,该钥匙也可以继续正常使用,不需要和接收端重新进行该钥匙的学习流程。

2, 信息交互与能力协商

三. Airplay 协议浅析

KSYAirStreamer SDK中的核心类KSYAirTunesServer实现了Airplay Screen Mirroring接收端的协议。

最大支持254个不同指令传输。

3, 音视频数据接收与解扰

3.1 Airplay 录屏SDK 难点分析

除了采用飞思卡尔提供的AES加密算法模块外,用户也可以根据需要(如缩小程序大小,减少解密时间)使用自己的加密算法模块。

设备广播与发现:

3.1.1 Airplay 协议文档缺失

AirPlay是Apple的私有协议族, 没有公开的官方文档作为参考. 目前能够参考的是github上nto大神整理的一份非官方的协议spec文档, 但是完全照着文档的描述是无法兼容新的iOS系统(iOS9/10)的, 新系统对协议有改变,而这份文档的最后更新日期是2012年, 这些变更内容都没有包含。

纯软件实现,可以灵活地使用于各类微控制器。

Airplay设备间的广播与发现通过Bonjour协议进行。Bonjour也被称为ZeroConf, mDNS等,可以用来在局域网内进行数据记录广播与发现。该协议比较成熟,网上可以找到诸多介绍。对于实现的Airplay(包括Mirroring)接收端而言,首先需要注册两类服务,即airtunes和airplay。 Airtunes服务主要用来处理广播视音频接收能力协商,是最为重要的服务内容,对应Bonjour记录名称为'_raop._tcp',注册服务端口不限,一般为了避免冲突,建议采用较高的端口数;Airplay服务主要用来兼容传统的streaming等服务,对应记录名称为'_airplay._tcp',注册端口一般为7000。

3.1.2 Airplay 敏感数据加密的破解

有人会说Airplay毕竟是通过网络交互的协议, 当年 nto能够整理出一份spec, 现在也可以通过抓包, 分析的方式得到新的交互过程, 缺少了文档不过是增加一些破解协议的难度而已. 但是以保护用户隐私著称的Apple, 不会明文传输音视频数据的. Airplay协议中有着比较完善的DRM保护, 传输的音视频都是用AES算法加密过的, 而AES的key 则是在握手的过程中通过Fairplay协议保护的, 这一部分是Apple重点保护的内容, 目前没有人能真正破解。

软件大小:不包含AES加密模块约为1.5K字节,如果含AES模块接近3K字节。软件以库函数的形式免费授权给采用飞思卡尔方案的客户使用。

具体的服务广播内容,可以进行局域网抓包,找到对应记录内容。

3.1.3 单机Airplay 录屏中音频采集的坑

使用Airplay的方案做录屏, 其实是接收端和客户端在同一设备上的,我们可以称之为单机Airplay. 正常的投屏过程中, 客户端会把音频投到接收设备上. 单机Airplay的话, 投屏的音频, 按逻辑还得继续投屏, 这时候就出现回环了. 因此录屏是必须通过一定的手段避免通过airplay传递音频, 强制保证音频还是通过外放(Speaker)播放. 再加上直播时还需要采集主播的声音. 这些与音频相关的操作都和iOS的AudioSession相关, 非常容易出现不稳定的情况。

VKSP的发送过程如图2。

当接收端通过Bonjour广播器服务能力后,发送端(如iPhone等各类iOS设备)就可以发现该接收端。

3.2 Airplay 协议可行性分析

Airplay的可行性主要是通过市面上已有的一些商业方案来保证的, 我们能看到reflector 2, 360 Mirroring 等收费的商业软件, 还有小米电视等机顶盒设备都有一些成功案例. 因此一定有人攻克以上的难点。

每次按下钥匙,将会产生一个发送帧。发送帧有两个部分:数据部分和消息验证码部分。数据部分不用加密,由三个部分共64位组成:钥匙号;用户命令;可变密钥,每次发送随时间和用户按键而增加,以确保即使用户命令相同,每次发送的消息帧内容也不会重复。消息验证码部分则有8个字节,由加密模块产生。

信息交互与能力协商:

3.3 Airplay 协议构成

AirPlay并不是完全重新开始写的一个协议, 是好几个现有的协议的组合, 其中有的协议是完全标准的, 有一部分协议进行了一些修改,有的则是完全私有的。

  • Multicast DNS (aka Bonjour) 用于发布服务, 启动后, 在iOS的控制中心菜单中就能看到对应的设备;
  • HTTP / RTSP / RTP 用于流媒体服务, 传输音视频数据, 进行播放控制等;
  • NTP 时间同步;
  • FairPlay DRM加密 完全私有的加密协议。

Airplay 在iOS上有很多种应用场景, 可以单独传输音频, 可以传输照片, 幻灯片, 可以直接传输本地播放的视频, 也可以直接投影屏幕内容. 不同应用场景协议交互的步骤也不同. 录屏应用主要是需要实现其中投影屏幕内容的部分交互协议。

接收过程分为三步,如图3。

当发送端发现接收端后,可以开始信息交互与能力协商过程。该部分协议协议格式类似rtsp协议格式。主要分为两个阶段,设备匹配与和能力协商。

3.4 Airplay Screen Mirroring

Airplay 录屏SDK内部的主要流程如下:

图片 5

airplay_flow

启动录屏时, 通过iOS上的 NSNetService API 实现Airplay的服务的发布, 服务发布的txtRecod里的字段比较关键, 其中有些字段决定了后续交互的内容, 比如加密方式等。

整个投影过程中有两个主要的网络连接, 接收端需要监听两个端口(airTunesPort,airVideoPort)。

其中, 通过airTunesPort建立的TCP连接主要完成的是建连握手部分, 通过airVideoPort建立的TCP连接用于传输 H.264编码的视频数据, 视频数据是被AES加密过的。

步骤一:接收端检查接收到的发送帧中的钥匙号是否存在于接收端存储的有效钥匙号数据库中,如果存在,则从接收端数据库中同时取出该钥匙对应的本地密钥(Local Key)和可变密钥(Variable Key),进入下一步骤,否则丢弃该帧。

当发送端链接服务端后,设备匹配过程即开始。通信双方会进行fairplay加密协议进行信息交换,当完成信息交换后,客户端后续必须使用这部分信息来处理加密过的密钥,才能获得进一步视音频解密密钥。在iOS9之后,在fairplay过程之前,增加一个设备匹配过程,即pair-setup、pair-verify过程,其主要算法是较为标准的非对称公钥交换算法。

3.5 Airplay 握手建连

建连握手部分是经过修改的RTSP协议, 与HTTP协议比较类似, 都是客户端(iOS系统)发起请求, 接收端SDK针对请求内容进行回应的方式. 每个请求包括:方法 路径 header content等内容。

主要的交互过程如下:

  1. 4次POST请求, 分别对应的路径为 /pair-setup, /pair-verify和两次/fp-setup 这是开头于FairPlay相关的核心加密部分, 任何一次POST的回复内容不对都会导致握手失败。
  2. SETUP请求 不同版本的iOS系统中, SETUP方法的次数可能不同.
    在SETUP方法中能得到比较多的信息, 比如后面视频AES解密需要用到的ekey和eiv. 接收端需要将自己的监听的接收端口airVideoPort回复给客户端.这些信息需要对这次请求的content使用Apple的Binary plist格式进行解码才能提取, 回复内容也要编码为Binary plist格式. 后续完成握手后, 客户端会通过 airVideoPort 端口建立 TCP连接, 然后将屏幕画面通过H.264编码后再通过AES加密处理后, 向连接持续发送。
  3. 一次GET请求, 路径为/info, 这里接收端需要回复一个Binary plist格式的数据, 将用户配置的画面分辨率, 最大帧率等信息传递到客户端。
  4. 可能有多次GET_PARAMETER和SET_PARAMETER请求用于调整音量大小。
  5. 一次RECORD请求, 表明握手完成, airplay镜像开始。
  6. 在镜像过程中会每秒都收到POST请求,路径为/feedback, 相当于心跳, 用于保持TCP的长连接。

步骤二:检查发送帧中的可变密钥是否大于步骤一中接收端数据库中该钥匙目前的可变密钥,如是,进入下一步骤,否则丢弃该帧。这一步骤保证了任何再次重复发送的帧不会被认为是有效帧。

当两端成功匹配后,开始进行能力协商与信息交换,这些信息包括,设备名称、代号,音视频接收相关端口配置,视频接收能力以及加密密钥等,相关信息使用binary plist格式进行封装。

3.6 Airplay Screen Mirroring 视频数据传输

视频数据传输是客户端通过TCP 单方向的往接收端灌加密后的数据. 数据内容分为头部和载荷. 头部包含了载荷的类型, 长度, 时间戳等信息. 载荷部分有两种, 一种是H.264的参数集, sps, pps等; 另一种就是AES加密后的H.264裸流, 没有填充到封装格式中, 用SETUP请求中得到的key和iv解密后,即可送到视频解码器中解码。

步骤三:进行消息码验证。由接收帧中的数据字段和从接收数据库中取出的该钥匙本地密钥通过加密模块生成消息验证码,由于发送端和接收端使用相同的加密模块,所以,如果发送端和接收端生成的两个消息验证码相同,则该帧被认为有效,用户命令被执行。同时,更新该钥匙当前的可变密钥至接收端数据库中。

可以参考

4. 总结

以上主要汇总了一下当前iOS平台上录屏的一些方案. 介绍了 基于Airplay Screen Mirroring的录屏SDK - KSYAirStreamer 的基本结构和使用方法。最后介绍了KSYAirStreamer中实现的Airplay协议的一些细节。希望能够帮到有录屏需求的同学.。
KSYAirStreamer 的demo大家可以到 github 查看代码和体验功能。

转载请注明:
作者金山视频云,首发简书 Jianshu.com


也欢迎大家使用我们的直播SDK:
iOS融合版(推流 播放):https://github.com/ksvc/KSYLive_iOS
有关音视频的更多精彩内容,请参考https://github.com/ksvc
金山云SDK相关的QQ交流群:

  • 视频云技术交流群:574179720
  • 视频云iOS技术交流:621137661

由上述过程可知,每一把新钥匙必须首先完成学习过程,即将该钥匙的钥匙号和本地密钥存储到接收端数据库以后,该钥匙才能被识别使用。为了系统的安全性,接收系统必须在指定的安全环境中处于被激活的状态下才进行学习帧的识别,例如用户在接收端按下一个特定的按键或者开关。图4表示了学习过程和学习帧的结构。

音视频数据接收与解密

图片 6

双方协商成功后,发送端开始向接收端发送视音频数据,mirroring数据是通过TCP进行发送,为h.264 ES流格式。音频是通过RTP协议进行发送,根据内容的不同音频编码为ALAC或者AAC-ELD。

接收端首先检查是否处于安全环境激活状态,从而决定是否进行学习帧识别。

音视频流都是通过AES进行了加密处理,密钥需要通过上面一步的进过信息交互后的fairplay模组对setup过程中接收到的加密密钥进行解密,获得的AES解密需要的IV和KEY,然后经过AES解扰,即可以获得最终的视音频清流。

发送端利用一个伪随机数发生器产生128位随机数,然后和厂商提供的128位OEM码(发送端和接收端必须共享同样的OEM码)通过加密模块产生128位输出数据,截取其中64位作为消息验证码,截取特定位数存储在发送端作为该钥匙本地密钥。同时,将该128位随机数和消息验证码通过两个连续的学习帧发送。两个学习帧分别由数值0XFE和0XFF特征码来识别。

其他需要注意的地方:

接收端通过特征码检测到学习帧并提取其中的128位随机数,然后依靠和发送端同样的厂商128位OEM码和加密模块完成消息验证码比对验证,又按照和发送端同样的输出截取方式生成和发送端相同的该钥匙本地密钥,最后将该本地密钥和钥匙号存储在接收端数据库中,从而完成该钥匙的学习过程。

Airplay没过Session传送过来的视频h264码流,只有开头一个关键帧. 因此这种情况并不适合直播这种需要固定GOP的场景. 还需要做进一步的转码的工作,或者直接在压缩域进行处理,获得合理的GOP结构。

综上所述,飞思卡尔半导体的RKE整体方案主要特点及其优势如下:

我们对Airplay相关协议的逆向工程已经封装成了跨平台的类库和框架, 支持windows/Mac/Android/iOS/linux, 在自己内部产品中使用已经非常稳定, 如果有需要可以联系我们. 也欢迎各类技术与应用场景讨论。我的邮箱 leeoxiang@gmail.com

系统选用通用MCU控制器,客户可以根据需要添加应用功能,增强了灵活性。

相关链接:

接收端不需要单独的解密芯片,解密算法集成在车身控制器中实现,简化了方案,节约了成本。

1)AirCast

钥匙端系统当没有用户按键时候,处于休眠状态,节省系统功耗。

2)Airplay Protocol

UHF接收芯片MC33596(或者双向收发芯片MC33696)支持304MHz到915MHz的OOK和FSK解调;片内支持数据曼彻斯特解码,节省了外部微控制器解码软件系统占用;具有片内定时唤醒、片脚唤醒并可设置特定帧唤醒外部MCU功能,节省系统功耗;同时支持两套系统参数配置。上述特性也使得该芯片还可以应用于被动无钥匙门禁系统和胎压检测系统中。

3)AirCast website

VKSP数据协议:纯软件实现,采用128位AES加密,增加了安全性;本地密钥在钥匙每次的学习过程中通过伪随机数发生器产生,所以对每把钥匙的每次学习过程将产生和存储不同的钥匙密钥,增强了保密性。

该方案评估系统实物如图5和图6。

图片 7

(文章来源:盖世汽车网)

本文版权为盖世汽车所有,欢迎转载!请务必注明出处及作者。

本文由星彩网app下载发布于计算机编程,转载请注明出处:投屏工夫详解,手机游戏直播方案相比较及Airp

TAG标签: 星彩网app下载
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。