目录
[1. 投屏方式](#1. 投屏方式 "#block_1")
[2. 投屏方案](#2. 投屏方案 "#block_2")
[3. DLNA协议详解](#3. DLNA协议详解 "#block_3")
1. 投屏方式
-
按照投屏后,展示端的数据来源,可以划分成两种主要的方式:推送投屏(Screencasting)和镜像投屏(ScreenMirroring)
-
通过一个表格看看两者的区别
推送投屏 镜像投屏 数据源 发送端向展示端发送url,此后由展示端从服务器获取媒体数据。 展示端从发送端获取数据,实时展示发送端画面。 优缺点 投屏后,手机使用不受限制,可以离开当前页面进行其他活动。但部分资源如文本等可能无法投屏。 实时展示手机画面,可以突破资源使用限制。但是手机不能离开当前页面。 使用场景 投屏多为音视频资源,主要应用在娱乐场景。如爱奇艺视频投屏等app内置投屏。 因不受资源限制,可以进行ppt展示等,主要应用在办公场景。如mac镜像等。
2. 投屏方案
- 2.1 Airplay
Airplay
是Apple推出的无线显示标准,因此其应用也就主要局限于Apple的生态之中。国内也有电视厂商实现了对Airplay
的破解,使得Apple设备可以投屏到安卓电视上。- 支持推送投屏和镜像投屏。
- 2.2 DLNA
DLNA(Digital Living Network Alliance)
是Sony于2003年发起的非营利性标准化组织,旨在制定在局域网内部进行多媒体文件及其信息共享的通信协议标准。DLNA的应用范围比较广泛,涵盖数字媒体设备、数字电视、车载娱乐等领域。大部分App内置投屏就是用的这个协议。- 支持推送投屏。
- 2.3 Miracast
Miracast
是2012年首次由WiFi Alliance发布,其底层采用了WiFi Direct
技术(点对点无线技术),因此不需要通过路由器,可以直接在两个设备之间建立P2P连接。目前对Miracast
支持最好的生态就是MircoSoft的Windows
系统了。- 支持镜像投屏。
- 2.4 Chromecast
- Google推出了
Chromecast
,Chromecast
是一款插在电视机HDMI接口上的无线设备,内置WIFI,可以通过WIFI与其他设备连接以及访问外网,类似一个迷你机顶盒。为了推广Chromecast
,Google还专门推出GoogleCastSDK
帮助APP开发者整合Chromecast
的推送功能。不过GoogleCastSDK
依赖于Google服务,在国内受到限制。 - 支持推送投屏。
- Google推出了
- 2.5 乐播投屏
- 乐播投屏是一套投屏技术方案,据官网称市面上90%的电视已采用乐播乐联协议,App开发者只需要接入乐播发送端SDK,即可同时支持
Airplay
,DLNA
,乐联(lelink)
协议等协议,兼容程度较高。但从2022年5月30日起,乐播投屏停止对旧版SDK的维护,新版SDK需要收费,按投屏日活进行收费。 - 详细内容可上官网查看:乐播
- 乐播投屏是一套投屏技术方案,据官网称市面上90%的电视已采用乐播乐联协议,App开发者只需要接入乐播发送端SDK,即可同时支持
3. DLNA详解
DLNA(Digital Living Network Alliance)
是一个组织并不是一个协议,这个组织定义了一套由基础协议组成的标准,所以用DLNA
指代投屏的一种实现方案好像也是可以的。
DLNA
是目前大部分电视机支持的投屏方案,不需要收费且有一些成熟的开源框架支持开发者接入,支持的投屏方式为推送投屏,满足App投屏的需要。下面从几个角度详细介绍DLNA
。
-
3.1 重要角色
DLNA
是推送投屏,涉及到发送控制端DMC
、接收端DMR
、数据存储服务端DMS
。DMR
:Digital Media Render
顾名思义就是渲染展示媒体数据的一端,比如我们的电视机。DMS
:Digital Media Server
用于保存音视频文件的存储服务器,属于比较范的一个概念。DMC
:Digital Media Controller
用于发现和控制的中间设备,发现局域网中存在的DMR
,然后把DMS
上的资源推送到DMR
上进行播放。
如果要把手机上的照片、视频文件推动到局域网内的电视上播放出来,手机就承担了
DMS
+DMC
的角色,而电视则是一个DMR
设备;而如果要在手机上控制电视播放B站的视频,手机就是
DMC
的角色,而电视就是DMR
设备。 -
3.2 原理
DLNA
的核心协议是UPnP
。UPnP体系允许PC间的点对点连接、网际互连和无线设备。它是一种基于TCP/IP、UDP和HTTP的分布式、开放体系。下面按步骤介绍DLNA
如何利用UPnP
完成投屏。-
发现设备 第一个步骤是发现设备。局域网内的设备,我们成为一个控制点
CP(ControlPoint)
,当一个新的CP
加入一个局域网时,为了获取当前网段里都有哪些智能设备,CP
需要遵循SSDP向默认多播IP和端口发送获取信息的请求。请求的格式如下:javaM-SEARCH * HTTP/1.1 MX: 1 //最大时间间隔数 ST: upnp:rootdevice //搜索的设备类型 MAN: "ssdp:discover" User-Agent: iOS 10.2.1 product/version Connection: close Host: 239.255.255.250 //多播地址
如果请求成功则返回如下信息:
javaHTTP/1.1 200 OK Cache-control: max-age=1800 Date: Thu, 16 Feb 2017 09:09:45 GMT LOCATION: http://10.2.9.152:49152/TxMediaRenderer_desc.xml //URL for UPnP description for device ... 省略不重要的信息 ST: upnp:rootdevice //device type
其中
LOCATION
代表一个xml
文件的链接,这个文件详细描述了当前局域网内CP
的信息。至此投屏的第一步完成,新加入的
CP
可以发现其他CP
。 -
描述设备 在上一步中,我们得到了一个
xml
链接,xml
文件的内容如下:xml<root xmlns="urn:schemas-upnp-org:device-1-0" xmlns:dlna="urn:schemas-dlna-org:device-1-0" configId="499354"> ... <device> <deviceType>urn:schemas-upnp-org:device:MediaRenderer:1</deviceType> <friendlyName>卧室的创维盒子Q+</friendlyName> ... <dlna:X_DLNADOC xmlns:dlna="urn:schemas-dlna-org:device-1-0">DMR-1.50</dlna:X_DLNADOC> <serviceList> <service> <serviceType>urn:schemas-upnp-org:service:AVTransport:1</serviceType> <serviceId>urn:upnp-org:serviceId:AVTransport</serviceId> <SCPDURL>/AVTransport/9c443d47158b-dmr/scpd.xml</SCPDURL> ... </service> ... </serviceList> </device> <device> ... </device> </root>
- device
device
描述了一个CP
的信息,每个device
对应局域网内的一个CP
。device
下的deviceType
描述了当前CP
的类型,MediaRenderer
代表当前CP
可以作为DMR
用于展示媒体资源。 - service
service
描述了当前CP
支持的服务,一般会有多个。service
的SCPDURL
指向另外一个xml
文件,这个文件描述了当前service
下支持的操作,如暂停、播放、快进等。
至此投屏的第二步完成,我们获取到
CP
的详细描述,包括设备的类型、支持的服务等。 - device
-
控制 在上一步中,我们得到了
SCPDURL
这个xml
链接,xml
文件的内容如下:xml<scpd xmlns="urn:schemas-upnp-org:service-1-0"> ... <actionList> <action> <name>SetAVTransportURI</name> <argumentList> <argument> <name>InstanceID</name> <direction>in</direction> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable> </argument> <argument> <name>CurrentURI</name> <direction>in</direction> <relatedStateVariable>AVTransportURI</relatedStateVariable> </argument> <argument> <name>CurrentURIMetaData</name> <direction>in</direction> <relatedStateVariable>AVTransportURIMetaData</relatedStateVariable> </argument> </action> ... </scpd>
- action 每个
action
代表一个操作,action
的argument
代表当前操作支持的参数。如上面的SetAVTransportURI
就是设置媒体的url。
执行这些
action
,需要按要求发起请求,请求的格式可以参考基于DLNA的移动端网络视频投屏技术初探。至此投屏的第三步完成,我们知道目标
CP
支持哪些操作,利用这些操作便可以完成我们的投屏及控制。这个过程中发起投屏的CP
便是DMC
,展示媒体资源的CP
便是DMS
。 - action 每个
-
-
3.3 相关开源框架 前面我们粗略的了解了
DLNA
的原理,DLNA
涉及的协议还是比较复杂的,人为的去处理这些请求和响应,还是比较麻烦的。所以社区中也有一些基于DLNA
的第三方框架可供我们使用,如:- cling 是基于
UPnP
的java
框架,对UPnP
进行了简单的封装,不支持纯ipv6的网络。 - cybergarage-upnp 是基于
UPnP
的java
框架,对UPnP
进行了简单的封装,不过代码结构不如cling
且存在getAction方法返回一直为空的问题,需要自己把jar包拉下来,然后修改其中的代码。 - DLNA-Cast 这个是目前发现比较完善的框架,是对
cling
的进一步封装,使用体验更好,目前还有在更新迭代,推荐使用。
- cling 是基于
-
3.4 安全性问题
- 投屏的时候,会把App的资源链接推送出去,可能涉及安全性。安全性问题怎么说呢?只能说防君子不防小人,即使像爱奇艺这样成熟的产品,还是会被盗取视频资源,只能通过一些手段提高盗取的成本。可以参考这个讨论,或许能找到一些思路。
- 在投屏这块,爱奇艺是用m3u8作为资源格式的。大致如下: setAVTransportURI: currentURI=cache.m.iqiyi.com/mus/8077509...