YAMBY 的 DLNA 请求对 URL 的编码有些问题

35 天前
 ihipop

不知道怎么联系作者就发这里吧. @Kivy

最近有机会接触三星的 Tizen TV 系统,发现 Yamby 的 DLNA 投屏功能对三星设备上某些功能不可用(无法播放),但是可以在 KODI 上正常使用,经过各种抓包测试,并且查阅了一些 DLNA 的上古文档,发现问题出在媒体文件的 metadata 上

YAMBY 的 DLNA 报文是这样的

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <u:SetAVTransportURI xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
      <InstanceID>0</InstanceID>
      <CurrentURI>http://192.168.0.214:9091/original.mp4?x=y&amp;z=z</CurrentURI>
      <CurrentURIMetaData>&lt;?xml version="1.0"?>&lt;DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/">&lt;item id="original.mp4" parentID="-1" restricted="1">&lt;dc:title>original.mp4&lt;/dc:title>&lt;upnp:class>object.item.videoItem&lt;/upnp:class>&lt;res protocolInfo="http-get:*:video/mp4:*;DLNA.ORG_OP=01;">http://192.168.0.214:9091/original.mp4?x=y&amp;z=z&lt;/res>&lt;/item>&lt;/DIDL-Lite></CurrentURIMetaData>
    </u:SetAVTransportURI>
  </s:Body>
</s:Envelope>

对于现代的 DLNA 设备来说 重点需要关注 CurrentURIMetaData

把他解码 是这样的内容

<?xml version="1.0"?>
<DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/">
  <item id="original.mp4" parentID="-1" restricted="1">
    <dc:title>original.mp4</dc:title>
    <upnp:class>object.item.videoItem</upnp:class>
    <res protocolInfo="http-get:*:video/mp4:*;DLNA.ORG_OP=01;">http://192.168.0.214:9091/original.mp4?x=y&z=z</res>
  </item>
</DIDL-Lite>

然后就会得到三丧电视答复如下内容

<?xml version="1.0" encoding="utf-8"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <s:Fault>
      <faultcode>s:Client</faultcode>
      <faultstring>UPnPError</faultstring>
      <detail>
        <UPnPError xmlns="urn:schemas-upnp-org:control-1-0">
          <errorCode>402</errorCode>
          <errorDescription>Invalid Args</errorDescription>
        </UPnPError>
      </detail>
    </s:Fault>
  </s:Body>
</s:Envelope>

其根本原因是因为, 在 XML 节点内的 URL 是需要进行 html 实体转义的, 也就是

CurrentURIMetaData 本身就是一个 html 实体转义后的 XML

其内的 URL 也必须是经过 html 实体转义的, 因为 XML 对某些字符(如 <, >, &, " 等)有严格的限制, 我们使用 YAMBY 主要的场景就是 EMBY 的 stream 拉流播放, 这个接口会通过 Query String 里面传递很多查询参数, 使用了大量的 &, 如果不进行实体转义, 就会对设备的解析造成问题

所以其实是 URL 转义以后的写入 DIDL-Lite ,然后 DIDL-Lite 再转义一次变成上面的样子, 其实就是 URL 被转义了两次.

所以如果一开始报文改成这样, 三星设备就会正确响应

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <u:SetAVTransportURI xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
      <InstanceID>0</InstanceID>
      <CurrentURI>http://192.168.0.214:9091/original.mp4?x=y&amp;z=z</CurrentURI>
      <CurrentURIMetaData>&lt;?xml version="1.0"?>&lt;DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/">&lt;item id="original.mp4" parentID="-1" restricted="1">&lt;dc:title>original.mp4&lt;/dc:title>&lt;upnp:class>object.item.videoItem&lt;/upnp:class>&lt;res protocolInfo="http-get:*:video/mp4:*;DLNA.ORG_OP=01;">http://192.168.0.214:9091/original.mkv?x=y&amp;amp;z=z&lt;/res>&lt;/item>&lt;/DIDL-Lite></CurrentURIMetaData>
    </u:SetAVTransportURI>
  </s:Body>
</s:Envelope>

另外这版的 Tizen 还有一个问题, 就是如果是 https 的 URL 不可以带端口号, 也就是, 报文里面写 https://example.com:443/example.mp4 是不可以的, 服务器会收到消息和完整的请求, 但是电视会显示错误信息, 并且拒绝播放.

很不幸, YAMBY 就是会带上端口号,哪怕是默认的(比如 https 的 默认端口是 443), 导致无法投屏

489 次点击
所在节点    全球工单系统
0 条回复

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1149751

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX