非官方AirPlay协议规范

1.导言

Airplay是由Apple实现的一系列协议,用于查看各种类型的媒体内容。苹果电视任何iOS设备或iTunes。在本文件中,“IOS设备“指的是iPhone、iPodtouch或iPad。AirPlay支持下列方案:

还支持从IOS设备或iTunes到机场快车基站或3的音频流。RD支持PartyAirPlay的音频设备。最初,这被称为AirTunes后来,当苹果公司增加了对Apple TV的视频支持时,它被改名为AirPlay。

本文档描述了这些协议,这些协议在Apple TV软件5.0、IOS 5.1和iTunes 10.6中实现。它们基于众所周知的标准网络协议,如组播DNS, http, RTSP, RTPNTP,具有自定义扩展。

所有这些信息都是利用各种逆向工程技术收集的,因此它们可能有些不准确和不完整。此外,本文件没有解释如何规避苹果公司实施的任何安全措施:

请不要把这件事发电子邮件给我,我不会回复的。事实上,所有这些实际上都不需要能够在Apple TV上查看媒体内容。

2.服务发现

Airplay不需要任何配置就可以在网络上找到兼容的设备,这要感谢基于dns的服务发现,基于组播DNS,又名亚细亚.

AirPlay设备,如AppleTV,发布了两项服务。第一个是RAOP (远程音频输出协议),用于音频流,另一种是AirPlay服务,用于照片和视频内容。

2.1.AirTunes服务

来自Apple TV的RAOP服务

name: 5855CA1AE288@Apple TV
type: _raop._tcp
port: 49152
txt:
 txtvers=1
 ch=2
 cn=0,1,2,3
 da=true
 et=0,3,5
 md=0,1,2
 pw=false
 sv=false
 sr=44100
 ss=16
 tp=UDP
 vn=65537
 vs=130.14
 am=AppleTV2,1
 sf=0x4

该名称是使用设备的MAC地址和将由客户端显示的远程扬声器的名称形成的。

以下字段出现在TXT记录中:

名字 价值 描述
txtvers 1 txt记录版本1
ch 2 音频通道:立体声
cn 0,1,2,3 音频编解码器
et 0,3,5 支持的加密类型
md 0,1,2 支持的元数据类型
pw 假的 扬声器需要密码吗?
sr 44100 音频采样率:44100 Hz
ss 16 音频样本大小:16位
tp UDP 支持传输:TCP或UDP
vs 130.14 server version 130.14
am AppleTV2,1 设备模型

音频编解码器

CN 描述
0 PCM
1 苹果无损耗(ALAC)
2 AAC
3 增强低延迟

加密类型

内皮素 描述
0 无加密
1 机场快线
3 费尔
4 MFiSAP(第三方设备)
5 FairPlay SAPv2.5

元数据类型

MD 描述
0 文本
1 艺术品
2 进展

2.2.空中播放服务

空中播放服务

name: Apple TV
type: _airplay._tcp
port: 7000
txt:
 deviceid=58:55:CA:1A:E2:88
 features=0x39f7
 model=AppleTV2,1
 srcvers=130.14

TXT记录中有以下字段:

名字 价值 描述
model AppleTV2,1 设备模型
deviceid 58:55:CA:1A:E2:88 设备的mac地址
features 0x39f7 支持特征位域
pw 1 服务器受密码保护

这个pw只有在AirPlay服务器受到密码保护时,才会出现字段。否则,它将不包含在TXT记录中。

这个features位域允许定义以下功能:

钻头 名字 描述
0 Video 视频支持
1 Photo 照片支持
2 VideoFairPlay 用FairPlay DRM保护视频
3 VideoVolumeControl 支持视频的音量控制
4 VideoHTTPLiveStreams 支持http实时流
5 Slideshow 幻灯片支持
7 Screen 镜像支持
8 ScreenRotate 屏幕旋转支撑
9 Audio 音频支持
11 AudioRedundant 支持音频包冗余
12 FPSAPv2pt5_AES_GCM 公平游戏安全保障
13 PhotoCaching 照片预压支撑

注意,Apple TV不支持VideoVolumeControl。它可能是为即将到来的苹果电视推出的。

AirPlay服务器是http服务器(RFC 2616)。与此服务器建立了两个连接,第二个连接被用作反向HTTP连接。这允许客户端从服务器接收异步事件,例如回放状态更改。

所有HTTP请求共享一些常见的标头:

名字 价值 描述
X-Apple-Session-ID 1bd6ceeb… 会话的UUID
X-Apple-Device-ID 0xdc2b61a0ce79 MAC地址

反向连接如下所示:

客户端→服务器

POST /reverse
Upgrade: PTTH/1.0
Connection: Upgrade
X-Apple-Purpose: event
Content-Length: 0
User-Agent: MediaControl/1.0
X-Apple-Session-ID: 1bd6ceeb-fffd-456c-a09c-996053a7a08c

服务器→客户端

HTTP/1.1 101 Switching Protocols
Date: Thu, 23 Feb 2012 17:33:41 GMT
Upgrade: PTTH/1.0
Connection: Upgrade

这个X-Apple-Purpose标头清楚地表明,此连接用于向客户端发送事件,而X-Apple-Session-ID用于将此连接链接到另一个(非反向)连接。事件使用POST请求将XML属性列表发送到/event地点。

3.照片

照片是JPEG使用PUT向AirPlay服务器请求。它们可以立即显示,也可以缓存以供将来使用。

3.1.http请求

获取/幻灯片-特性

客户端可以获取幻灯片显示的可用转换列表。然后,它可以让用户选择一个,然后开始幻灯片。这个Accept-Language标头用于指定转换名称应该使用哪种语言。

客户端→服务器

GET /slideshow-features HTTP/1.1
Accept-Language: English
Content-Length: 0
User-Agent: MediaControl/1.0
X-Apple-Session-ID: cdda804c-33ae-4a0b-a5f2-f0e532fd5abd

服务器→客户端

HTTP/1.1 200 OK
Date: Thu, 23 Feb 2012 17:33:41 GMT
Content-Type: text/x-apple-plist+xml
Content-Length: 6411

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
 <dict>
  <key>themes</key>
  <array>
   <dict>
    <key>key</key>
    <string>Reflections</string>
    <key>name</key>
    <string>Reflections</string>
   </dict>
   ...
  </array>
 </dict>
</plist>

放/照

向服务器发送JPEG图片。支持下列标题:

名字 描述
X-Apple-AssetKey 图片的UUID
X-Apple-Transition 应该用来显示图片的转换。
X-Apple-AssetAction 指定缓存操作

例1:在没有任何过渡的情况下显示图片(这是第一次)

客户端→服务器

PUT /photo HTTP/1.1
X-Apple-AssetKey: F92F9B91-954E-4D63-BB9A-EEC771ADE6E8
Content-Length: 462848
User-Agent: MediaControl/1.0
X-Apple-Session-ID: 1bd6ceeb-fffd-456c-a09c-996053a7a08c

<JPEG DATA>

服务器→客户端

HTTP/1.1 200 OK
Date: Thu, 23 Feb 2012 17:33:42 GMT
Content-Length: 0

例2:使用溶解过渡显示图片

客户端→服务器

PUT /photo HTTP/1.1
X-Apple-AssetKey: F92F9B91-954E-4D63-BB9A-EEC771ADE6E8
X-Apple-Transition: Dissolve
Content-Length: 462848
User-Agent: MediaControl/1.0
X-Apple-Session-ID: 1bd6ceeb-fffd-456c-a09c-996053a7a08c

<JPEG DATA>

服务器→客户端

HTTP/1.1 200 OK
Date: Thu, 23 Feb 2012 17:33:42 GMT
Content-Length: 0

放置/幻灯片/1

启动或停止幻灯片会话。启动时,将传输幻灯片设置,如幻灯片持续时间和选定的过渡主题。以下参数在XML属性列表中发送:

钥匙 类型 描述
settings.slideDuration 整型 幻灯片持续时间(秒)
settings.theme 选定的过渡主题
国家 playingstopped

例子:发送幻灯片设置

客户端→服务器

PUT /slideshows/1 HTTP/1.1
Content-Type: text/x-apple-plist+xml
Content-Length: 366
User-Agent: MediaControl/1.0
X-Apple-Session-ID: 98a7b246-8e00-49a6-8765-db57165f5b67

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
 <dict>
  <key>settings</key>
  <dict>
   <key>slideDuration</key>
   <integer>3</integer>
   <key>theme</key>
   <string>Classic</string>
  </dict>
  <key>state</key>
  <string>playing</string>
 </dict>
</plist>

服务器→客户端

HTTP/1.1 200 OK
Date: Thu, 08 Mar 2012 16:30:01 GMT
Content-Type: text/x-apple-plist+xml
Content-Length: 181

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
 <dict/>
</plist>

后/停

停止照片或幻灯片会话。

客户端→服务器

POST /stop HTTP/1.1
Content-Length: 0
User-Agent: MediaControl/1.0
X-Apple-Session-ID: 1bd6ceeb-fffd-456c-a09c-996053a7a08c

服务器→客户端

HTTP/1.1 200 OK
Date: Thu, 23 Feb 2012 17:33:55 GMT
Content-Length: 0

3.2.事件

照片

此事件通知客户端照片会话已结束。然后服务器可以安全地断开连接。

钥匙 类型 描述
范畴 photo
会话ID 整型 会话ID
国家 stopped

例子:停止照片会话

服务器→客户端

POST /event HTTP/1.1
Content-Type: text/x-apple-plist+xml
Content-Length: 277
X-Apple-Session-ID: 1bd6ceeb-fffd-456c-a09c-996053a7a08c

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
 <dict>
  <key>category</key>
  <string>photo</string>
  <key>sessionID</key>
  <integer>38</integer>
  <key>state</key>
  <string>stopped</string>
 </dict>
</plist>

客户端→服务器

HTTP/1.1 200 OK
Content-Length: 0

幻灯片

幻灯片事件用于将播放状态通知服务器。

钥匙 类型 描述
范畴 slideshow
最后资产ID 整型 最后资产ID
会话ID 整型 会话ID
国家 loading, playingstopped

例子:幻灯片正在播放

服务器→客户端

POST /event HTTP/1.1
Content-Type: text/x-apple-plist+xml
Content-Length: 371
X-Apple-Session-ID: f1634b51-5cae-4384-ade5-54f4159a15f1

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
 <dict>
  <key>category</key>
  <string>slideshow</string>
  <key>lastAssetID</key>
  <integer>5</integer>
  <key>sessionID</key>
  <integer>4</integer>
  <key>state</key>
  <string>playing</string>
 </dict>
</plist>

客户端→服务器

HTTP/1.1 200 OK
Content-Length: 0

3.3.照片缓存

Airplay支持预加载图片数据,以提高转换延迟。这是通过在显示一张图片之后预装几张图片(很可能是当前图片之前和之后的图片)来实现的。

使用cacheOnly资产行动。收到此请求后,服务器将图片存储在其缓存中。稍后,客户端可以使用displayCached资产操作和相同的资产密钥。这比一个完整的图片上传要快得多,因为没有传输额外的数据。

当被要求获得已不在缓存中的图片时,服务器将使用HTTP 412错误代码进行应答(前提条件失败)。

例1:缓存图片以供将来显示

客户端→服务器

PUT /photo HTTP/1.1
X-Apple-AssetAction: cacheOnly
X-Apple-AssetKey: B0DDE2C0-6FDD-48F8-9E5B-29CE0618DF5B
Content-Length: 462848
User-Agent: MediaControl/1.0
X-Apple-Session-ID: 1bd6ceeb-fffd-456c-a09c-996053a7a08c

<JPEG DATA>

服务器→客户端

HTTP/1.1 200 OK
Date: Thu, 23 Feb 2012 17:33:45 GMT
Content-Length: 0

例2:显示缓存的图片

客户端→服务器

PUT /photo HTTP/1.1
X-Apple-AssetAction: displayCached
X-Apple-AssetKey: B0DDE2C0-6FDD-48F8-9E5B-29CE0618DF5B
X-Apple-Transition: Dissolve
Content-Length: 0
User-Agent: MediaControl/1.0
X-Apple-Session-ID: 1bd6ceeb-fffd-456c-a09c-996053a7a08c

服务器→客户端

HTTP/1.1 200 OK
Date: Thu, 23 Feb 2012 17:33:45 GMT
Content-Length: 0

3.4.幻灯片

幻灯片使用反向HTTP连接异步加载图片。三个连接并行执行。这个X-Apple-Purpose标头设置为slideshow。一个GET/slideshows/1/assets/1发出位置以从AirPlay客户端获取新图片。具有下列参数的二进制属性列表应作为答复:

钥匙 类型 描述
数据 数据 JPEG图像
info.id 整型 资产ID
info.key 整型 1

例子:取一张新图片

服务器→客户端

GET /slideshows/1/assets/1 HTTP/1.1
Content-Length: 0
Accept: application/x-apple-binary-plist
X-Apple-Session-ID: 98a7b246-8e00-49a6-8765-db57165f5b67

客户端→服务器

HTTP/1.1 200 OK
Content-Type: application/x-apple-binary-plist
Content-Length: 58932

<BINARY PLIST DATA>

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
 <dict>
  <key>data</key>
  <data>
  ...
  </data>
  <key>info</key>
  <dict>
   <key>id</key>
   <integer>1</integer>
   <key>key</key>
   <string>1</string>
  </dict>
 </dict>
</plist>

4.录像

为了在AirPlay服务器上播放视频,HTTP请求用于发送视频URL、执行擦除、更改播放速率和更新时间线。

4.1.http请求

获取/服务器-信息

获取有关AirPlay服务器的一般信息。这些信息作为XML属性列表返回,并具有以下属性:

钥匙 类型 价值 描述
设备ID 58:55:CA:1A:E2:88 MAC地址
特征 整型 14839 0x39f7
模型 AppleTV2,1 设备模型
原机 1.0 协议版本
斯克弗斯 120.2 服务器版本

这个model, deviceid, srcversfeatures属性与由mdns AirPlay服务广播的相同。

例子:获取服务器信息

客户端→服务器

GET /server-info HTTP/1.1
X-Apple-Device-ID: 0xdc2b61a0ce79
Content-Length: 0
User-Agent: MediaControl/1.0
X-Apple-Session-ID: 1bd6ceeb-fffd-456c-a09c-996053a7a08c

服务器→客户端

HTTP/1.1 200 OK
Date: Thu, 23 Feb 2012 17:33:41 GMT
Content-Type: text/x-apple-plist+xml
Content-Length: 427

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
 <dict>
  <key>deviceid</key>
  <string>58:55:CA:1A:E2:88</string>
  <key>features</key>
  <integer>14839</integer>
  <key>model</key>
  <string>AppleTV2,1</string>
  <key>protovers</key>
  <string>1.0</string>
  <key>srcvers</key>
  <string>120.2</string>
 </dict>
</plist>

后/戏

开始播放视频。主体包含以下参数:

名字 类型 描述
Content-Location URL 视频的URL
Start-Position 浮子 0到1之间的起始位置

使用渐进下载支持MP4电影。HTTP实况流也可能被支持,如VideoHTTPLiveStreams特征标志。相对起始位置,在0(开始)和1(结束)之间的浮点值用于在与客户端完全相同的位置开始播放视频。

还可以使用具有内容类型的二进制属性列表代替文本参数。application/x-apple-binary-plist.

例1:从iTunes播放视频

客户端→服务器

POST /play HTTP/1.1
User-Agent: iTunes/10.6 (Macintosh; Intel Mac OS X 10.7.3) AppleWebKit/535.18.5
Content-Length: 163
Content-Type: text/parameters

Content-Location: http://192.168.1.18:3689/airplay.mp4?database-spec='dmap.persistentid:0x63b5e5c0c201542e'&item-spec='dmap.itemid:0x21d'
Start-Position: 0.174051

服务器→客户端

HTTP/1.1 200 OK
Date: Mon, 08 Mar 2012 18:08:25 GMT
Content-Length: 0

例2:iPhone视频回放

客户端→服务器

POST /play HTTP/1.1
X-Transmit-Date: 2012-03-16T14:20:39.656533Z
Content-Type: application/x-apple-binary-plist
Content-Length: 491
User-Agent: MediaControl/1.0
X-Apple-Session-ID: 368e90a4-5de6-4196-9e58-9917bdd4ffd7

<BINARY PLIST DATA>

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
 <dict>
  <key>Content-Location</key>
  <string>http://redirector.c.youtube.com/videoplayback?...</string>
  <key>Start-Position</key>
  <real>0.024613151326775551</real>
 </dict>
</plist>

服务器→客户端

HTTP/1.1 200 OK

员额/擦洗b

在视频中寻找任意位置。这个position参数是一个浮点值,表示该位置(以秒为单位)。

例子:争取20秒左右

客户端→服务器

POST /scrub?position=20.097000 HTTP/1.1
User-Agent: iTunes/10.6 (Macintosh; Intel Mac OS X 10.7.3) AppleWebKit/535.18.5
Content-Length: 0

服务器→客户端

HTTP/1.1 200 OK
Date: Mon, 08 Mar 2012 18:08:42 GMT
Content-Length: 0

员额/费率

改变播放率。这个value参数是表示播放速率的浮点值:0暂停,1以正常速度播放。

例子:暂停回放

客户端→服务器

POST /rate?value=0.000000 HTTP/1.1
User-Agent: iTunes/10.6 (Macintosh; Intel Mac OS X 10.7.3) AppleWebKit/535.18.5
Content-Length: 0

服务器→客户端

HTTP/1.1 200 OK
Date: Mon, 08 Mar 2012 18:08:37 GMT
Content-Length: 0

后/停

停止播放。

例子:停止播放

客户端→服务器

POST /stop HTTP/1.1
User-Agent: iTunes/10.6 (Macintosh; Intel Mac OS X 10.7.3) AppleWebKit/535.18.5
Content-Length: 0

服务器→客户端

HTTP/1.1 200 OK
Date: Mon, 08 Mar 2012 18:09:06 GMT
Content-Length: 0

获得/擦洗

检索当前播放位置。可以反复调用它来更新客户端上的时间线。返回下列参数:

名字 类型 描述
duration 浮子 持续时间(以秒为单位)
position 浮子 以秒为单位的位置

例子:获取当前回放过程

客户端→服务器

GET /scrub HTTP/1.1
User-Agent: iTunes/10.6 (Macintosh; Intel Mac OS X 10.7.3) AppleWebKit/535.18.5
Content-Length: 0

服务器→客户端

HTTP/1.1 200 OK
Date: Mon, 08 Mar 2012 18:08:31 GMT
Content-Type: text/parameters
Content-Length: 40

duration: 83.124794
position: 14.467000

获取/播放-信息

检索回放信息,如位置、持续时间、速率、缓冲状态等。返回带有以下参数的XML属性列表:

钥匙 类型 描述
duration 真品 播放持续时间(秒)
position 真品 播放位置(秒)
rate 真品 回放率
readyToPlay 布尔型 准备玩
playbackBufferEmpty 布尔型 缓冲空
playbackBufferFull 布尔型 缓冲满
playbackLikelyToKeepUp 布尔型 回放可能会跟上
loadedTimeRanges 列阵 加载时间范围数组
seekableTimeRanges 列阵 可寻时间范围阵列

范围被定义为具有以下键的字典:

钥匙 类型 描述
start 真品 距离启动时间(以秒为单位)
duration 真品 范围持续时间(以秒为单位)

例子:获取播放信息

客户端→服务器

GET /playback-info HTTP/1.1
Content-Length: 0
User-Agent: MediaControl/1.0
X-Apple-Session-ID: 24b3fd94-1b6d-42b1-89a3-47108bfbac89

服务器→客户端

HTTP/1.1 200 OK
Date: Fri, 16 Mar 2012 15:31:42 GMT
Content-Type: text/x-apple-plist+xml
Content-Length: 801
X-Transmit-Date: 2012-03-16T15:31:42.607066Z

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
 <dict>
  <key>duration</key> <real>1801</real>
  <key>loadedTimeRanges</key>
  <array>
   <dict>
    <key>duration</key> <real>51.541130402</real>
    <key>start</key> <real>18.118717650000001</real>
   </dict>
  </array>
  <key>playbackBufferEmpty</key> <true/>
  <key>playbackBufferFull</key> <false/>
  <key>playbackLikelyToKeepUp</key> <true/>
  <key>position</key> <real>18.043869775000001</real>
  <key>rate</key> <real>1</real>
  <key>readyToPlay</key> <true/>
  <key>seekableTimeRanges</key>
  <array>
   <dict>
    <key>duration</key>
    <real>1801</real>
    <key>start</key>
    <real>0.0</real>
   </dict>
  </array>
 </dict>
</plist>

PUT/setProperty

设置播放属性。属性名称作为查询参数发送。定义了以下属性:

论辩 描述
forwardEndTime 前结束时间
reverseEndTime 反向结束时间

例子:预先设定结束时间

客户端→服务器

PUT /setProperty?forwardEndTime HTTP/1.1
Content-Type: application/x-apple-binary-plist
Content-Length: 96
User-Agent: MediaControl/1.0
X-Apple-Session-ID: 24b3fd94-1b6d-42b1-89a3-47108bfbac89

<BINARY PLIST DATA>

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
 <dict>
  <key>value</key>
  <dict>
   <key>epoch</key> <integer>0</integer>
   <key>flags</key> <integer>0</integer>
   <key>timescale</key> <integer>0</integer>
   <key>value</key> <integer>0</integer>
  </dict>
 </dict>
</plist>

服务器→客户端

HTTP/1.1 200 OK
Date: Fri, 16 Mar 2012 15:23:11 GMT
Content-Type: application/x-apple-binary-plist
Content-Length: 58

<BINARY PLIST DATA>

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
 <dict>
  <key>errorCode</key>
  <integer>0</integer>
 </dict>
</plist>

获取/getProperty

获取播放属性。属性名称作为查询参数发送。定义了以下属性:

论辩 描述
playbackAccessLog 回放存取日志
playbackErrorLog 回放错误日志

例子:获取回放访问日志

客户端→服务器

POST /getProperty?playbackAccessLog HTTP/1.1
Content-Type: application/x-apple-binary-plist
Content-Length: 0
User-Agent: MediaControl/1.0
X-Apple-Session-ID: 24b3fd94-1b6d-42b1-89a3-47108bfbac89

服务器→客户端

HTTP/1.1 200 OK
Date: Fri, 16 Mar 2012 15:31:42 GMT
Content-Type: application/x-apple-binary-plist
Content-Length: 530

<BINARY PLIST DATA>

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
 <dict>
  <key>errorCode</key>
  <integer>0</integer>
  <key>value</key>
  <array>
   <dict>
    <key>bytes</key> <integer>1818336</integer>
    <key>c-duration-downloaded</key> <real>70</real>
    <key>c-duration-watched</key> <real>18.154102027416229</real>
    <key>c-frames-dropped</key> <integer>0</integer>
    <key>c-observed-bitrate</key> <real>14598047.302367469</real>
    <key>c-overdue</key> <integer>0</integer>
    <key>c-stalls</key> <integer>0</integer>
    <key>c-start-time</key> <real>0.0</real>
    <key>c-startup-time</key> <real>0.27732497453689575</real>
    <key>cs-guid</key> <string>B475F105-78FD-4200-96BC-148BAB6DAC11</string>
    <key>date</key> <date>2012-03-16T15:31:24Z</date>
    <key>s-ip</key> <string>213.152.6.89</string>
    <key>s-ip-changes</key> <integer>0</integer>
    <key>sc-count</key> <integer>7</integer>
    <key>uri</key> <string>http://devimages.apple.com/iphone/samples/bipbop/gear1/prog_index.m3u8</string>
   </dict>
  </array>
 </dict>
</plist>

4.2.事件

此事件用于向客户端发送回放状态:

钥匙 类型 描述
范畴 video
会话ID 整型 会话id
国家 loading, playing, pausedstopped

例子:通知客户端视频播放暂停

服务器→客户端

POST /event HTTP/1.1
Content-Type: application/x-apple-plist
Content-Length: 321
X-Apple-Session-ID: 00000000-0000-0000-0000-000000000000

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
 <dict>
  <key>category</key>
  <string>video</string>
  <key>sessionID</key>
  <integer>13</integer>
  <key>state</key>
  <string>paused</string>
 </dict>
</plist>

客户端→服务器

HTTP/1.1 200 OK
Content-Length: 0
Date: Mon, 08 Mar 2012 18:07:43 GMT

5.音频

控件支持音频流。RTSP议定书(RFC 2326).

5.1.RTSP请求

备选方案

这个OPTIONS请求请求RTSP服务器提供其支持的方法。AppleTV支持以下方法:ANNOUNCE, SETUP, RECORD, PAUSE, FLUSH, TEARDOWN, OPTIONS, GET_PARAMETER, SET_PARAMETER, POSTGET.

客户端→服务器

OPTIONS * RTSP/1.0
CSeq: 3
User-Agent: iTunes/10.6 (Macintosh; Intel Mac OS X 10.7.3) AppleWebKit/535.18.5
Client-Instance: 56B29BB6CB904862
DACP-ID: 56B29BB6CB904862
Active-Remote: 1986535575

服务器→客户端

RTSP/1.0 200 OK
Public: ANNOUNCE, SETUP, RECORD, PAUSE, FLUSH, TEARDOWN, OPTIONS,
GET_PARAMETER, SET_PARAMETER, POST, GET
Server: AirTunes/130.14
CSeq: 3

宣布

这个ANNOUNCE请求将使用SDP的流属性告知RTSP服务器(RFC 4566)。编解码信息和加密密钥是特别感兴趣的。

例1: ANNOUNCE苹果无损来自iTunes的音频

客户端→服务器

ANNOUNCE rtsp://fe80::217:f2ff:fe0f:e0f6/3413821438 RTSP/1.0
CSeq: 3
Content-Type: application/sdp
Content-Length: 348
User-Agent: iTunes/10.6 (Macintosh; Intel Mac OS X 10.7.3) AppleWebKit/535.18.5
Client-Instance: 56B29BB6CB904862
DACP-ID: 56B29BB6CB904862
Active-Remote: 1986535575

v=0
o=iTunes 3413821438 0 IN IP4 fe80::217:f2ff:fe0f:e0f6
s=iTunes
c=IN IP4 fe80::5a55:caff:fe1a:e187
t=0 0
m=audio 0 RTP/AVP 96
a=rtpmap:96 AppleLossless
a=fmtp:96 352 0 16 40 10 14 2 255 0 0 44100
a=fpaeskey:RlBMWQECAQAAAAA8AAAAAPFOnNe+zWb5/n4L5KZkE2AAAAAQlDx69reTdwHF9LaNmhiRURTAbcL4brYAceAkZ49YirXm62N4
a=aesiv:5b+YZi9Ikb845BmNhaVo+Q

服务器→客户端

RTSP/1.0 200 OK
Server: AirTunes/130.14
CSeq: 3

例2: ANNOUNCEAAC来自IOS设备的音频

客户端→服务器

ANNOUNCE rtsp://192.168.1.45/2699324803567405959 RTSP/1.0
X-Apple-Device-ID: 0xa4d1d2800b68
CSeq: 16
DACP-ID: 14413BE4996FEA4D
Active-Remote: 2543110914
Content-Type: application/sdp
Content-Length: 331

v=0
o=AirTunes 2699324803567405959 0 IN IP4 192.168.1.5
s=AirTunes
c=IN IP4 192.168.1.5
t=0 0
m=audio 0 RTP/AVP 96
a=rtpmap:96 mpeg4-generic/44100/2
a=fmtp:96
a=fpaeskey:RlBMWQECAQAAAAA8AAAAAOG6c4aMdLkXAX+lbjp7EhgAAAAQeX5uqGyYkBmJX+gd5ANEr+amI8urqFmvcNo87pR0BXGJ4eLf
a=aesiv:VZTaHn4wSJ84Jjzlb94m0Q==
a=min-latency:11025

服务器→客户端

RTSP/1.0 200 OK
Server: AirTunes/130.14
CSeq: 16

例3: ANNOUNCEAAC-ELD音频和H.264来自IOS设备的视频

客户端→服务器

ANNOUNCE rtsp://192.168.1.45/846700446248110360 RTSP/1.0
X-Apple-Device-ID: 0xa4d1d2800b68
CSeq: 27
DACP-ID: 14413BE4996FEA4D
Active-Remote: 2543110914
Content-Type: application/sdp
Content-Length: 415

v=0
o=AirTunes 846700446248110360 0 IN IP4 192.168.1.5
s=AirTunes
c=IN IP4 192.168.1.5
t=0 0
m=audio 0 RTP/AVP 96
a=rtpmap:96 mpeg4-generic/44100/2
a=fmtp:96 mode=AAC-eld; constantDuration=480
a=fpaeskey:RlBMWQECAQAAAAA8AAAAAKKp+t27A+686xfviEphhw8AAAAQE/3LSqv9MHgnEKxkbKh1buE9+ylKg0YuqcyAC7fT0EqJNtdq
a=aesiv:i/a3nUKYNDSIPP2fC+UKGQ==
a=min-latency:4410
m=video 0 RTP/AVP 97
a=rtpmap:97 H264
a=fmtp:97

服务器→客户端

RTSP/1.0 200 OK
Server: AirTunes/130.14
CSeq: 27

设置

这个SETUP请求初始化记录会话。它发送所有必要的运输信息。设置了三个UDP通道:

通道 描述
服务器 音频数据
控制 同步和重传请求
计时 主时钟同步

例子:设置记录会话

客户端→服务器

SETUP rtsp://fe80::217:f2ff:fe0f:e0f6/3413821438 RTSP/1.0
CSeq: 4
Transport: RTP/AVP/UDP;unicast;interleaved=0-1;mode=record;control_port=6001;timing_port=6002
User-Agent: iTunes/10.6 (Macintosh; Intel Mac OS X 10.7.3) AppleWebKit/535.18.5
Client-Instance: 56B29BB6CB904862
DACP-ID: 56B29BB6CB904862
Active-Remote: 1986535575

服务器→客户端

RTSP/1.0 200 OK
Transport: RTP/AVP/UDP;unicast;mode=record;server_port=53561;control_port=63379;timing_port=50607
Session: 1
Audio-Jack-Status: connected
Server: AirTunes/130.14
CSeq: 4

记录

这个RECORD请求启动音频流。这个RTP-Info标头包含以下参数:

名字 大小 描述
seq 16位 初始RTP序列号
rtptime 32位 初始RTP时间戳

例子:启动音频流

客户端→服务器

RECORD rtsp://fe80::217:f2ff:fe0f:e0f6/3413821438 RTSP/1.0
CSeq: 5
Session: 1
Range: npt=0-
RTP-Info: seq=20857;rtptime=1146549156
User-Agent: iTunes/10.6 (Macintosh; Intel Mac OS X 10.7.3) AppleWebKit/535.18.5
Client-Instance: 56B29BB6CB904862
DACP-ID: 56B29BB6CB904862
Active-Remote: 1986535575

服务器→客户端

RTSP/1.0 200 OK
Audio-Latency: 2205
Server: AirTunes/130.14
CSeq: 5

冲水

这个FLUSH请求停止流。

例子:暂停音频流

客户端→服务器

FLUSH rtsp://fe80::217:f2ff:fe0f:e0f6/3413821438 RTSP/1.0
CSeq: 31
Session: 1
RTP-Info: seq=25009;rtptime=1148010660
User-Agent: iTunes/10.6 (Macintosh; Intel Mac OS X 10.7.3) AppleWebKit/535.18.5
Client-Instance: 56B29BB6CB904862
DACP-ID: 56B29BB6CB904862
Active-Remote: 1986535575

服务器→客户端

RTSP/1.0 200 OK
RTP-Info: rtptime=1147914212
Server: AirTunes/130.14
CSeq: 31

拆下

这个TEARDOWN请求结束RTSP会话。

例子:闭幕会议1

客户端→服务器

TEARDOWN rtsp://fe80::217:f2ff:fe0f:e0f6/3413821438 RTSP/1.0
CSeq: 32
Session: 1
User-Agent: iTunes/10.6 (Macintosh; Intel Mac OS X 10.7.3) AppleWebKit/535.18.5
Client-Instance: 56B29BB6CB904862
DACP-ID: 56B29BB6CB904862
Active-Remote: 1986535575

服务器→客户端

RTSP/1.0 200 OK
Server: AirTunes/130.14
CSeq: 32

5.2.RTP流

音频包完全符合RTP。然而,控制和定时包似乎并不完全符合RTP标准。

定义了以下有效载荷类型:

有效载荷类型 描述
82 timing_port 定时请求
83 timing_port 定时回复
84 control_port 时间同步
85 control_port 重传请求
86 control_port 重发回复
96 server_port 音频数据

音频包

音频数据使用DynamicRTP-Type-96有效载荷类型。这个Marker后发送的第一个数据包上设置了位。RECORDFLUSH请求。RTP有效负载包含可选加密的音频数据。

例子:加密音频包

客户端→服务器

0000   80 e0 b1 91 f7 79 16 c2 e8 bb 6b 2c bb 5c 8e 51
0010   aa 7c d2 96 00 c3 fd 60 eb ae 6e 41 31 38 fe ae
....
03e0   cb 1c 73 bf e7 05 93 30 fa 85 7f 32 77 8d a8 97
03f0   a0 c7 c8 78 7b e5 81 a1 4f b4 3e a3 43 db 7c

Real-Time Transport Protocol
    10.. .... = Version: RFC 1889 Version (2)
    ..0. .... = Padding: False
    ...0 .... = Extension: False
    .... 0000 = Contributing source identifiers count: 0
    1... .... = Marker: True
    Payload type: DynamicRTP-Type-96 (96)
    Sequence number: 45457
    Timestamp: 4151908034
    Synchronization Source identifier: 0xe8bb6b2c (3904596780)
    Payload: bb5c8e51aa7cd29600c3fd60ebae6e413138feae909b44f1...

同步包

同步数据包每秒发送一次到控制端口。它们用于将当前在音频流中使用的RTP时间戳与用于时钟同步的NTP时间关联起来。有效载荷类型为84,Marker位总是被设置,并且Extension后在第一个数据包上设置位。RECORDFLUSH请求。这个SSRC字段不包含在RTP头中。

字节 描述
8 RTP头SSRC
8 电流NTP时间
4 下一个音频包的RTP时间戳

例子:同步包

客户端→服务器

0000   80 d4 00 04 c7 cd 11 a8 83 ab 1c 49 2f e4 22 e2
0010   c7 ce 3f 1f

Real-Time Transport Protocol
    10.. .... = Version: RFC 1889 Version (2)
    ..0. .... = Padding: False
    ...0 .... = Extension: False
    .... 0000 = Contributing source identifiers count: 0
    1... .... = Marker: True
    Payload type: Unassigned (84)
    Sequence number: 4
    Timestamp: 3352105384
    Synchronization Source identifier: 0x83ab1c49 (2209029193)
    Payload: 2fe422e2c7ce3f1f

重传分组

AirTunes支持重发已丢失的音频数据包。重传查询的有效负载类型为85,Marker位总是被设置,并且SSRC字段不包含在RTP头中。

字节 描述
8 RTP头SSRC
2 第一个丢失数据包的序列号
2 丢失数据包数

重传应答具有86类型的有效负载,在序列号之后有一个完整的音频RTP数据包。

定时包

定时分组用于同步用于音频的主时钟。这对于几个播放相同音频流的设备的时钟恢复和精确同步非常有用。

定时分组以3秒间隔发送。他们总是Marker位设置,有效负载类型82用于查询,83类型用于答复。这个SSRC字段不包含在RTP头中,因此它只需要8个字节,然后是3个字节。NTP时间戳:

字节 描述
8 RTP头SSRC
8 起始时间戳
8 接收时间戳
8 发送时间戳

例子:定时查询/答复

服务器→客户端

0000   80 d2 00 07 00 00 00 00 00 00 00 00 00 00 00 00
0010   00 00 00 00 00 00 00 00 83 c1 17 cc af ba 9b 32

Real-Time Transport Protocol
    10.. .... = Version: RFC 1889 Version (2)
    ..0. .... = Padding: False
    ...0 .... = Extension: False
    .... 0000 = Contributing source identifiers count: 0
    1... .... = Marker: True
    Payload type: Unassigned (82)
    Sequence number: 7
    Timestamp: 0
    Synchronization Source identifier: 0x00000000 (0)
    Payload: 00000000000000000000000083c117ccafba9b32

客户端→服务器

0000   80 d3 00 07 00 00 00 00 83 c1 17 cc af ba 9b 32
0010   83 c1 17 cc b0 12 ce b6 83 c1 17 cc b0 14 10 47

Real-Time Transport Protocol
    10.. .... = Version: RFC 1889 Version (2)
    ..0. .... = Padding: False
    ...0 .... = Extension: False
    .... 0000 = Contributing source identifiers count: 0
    1... .... = Marker: True
    Payload type: Unassigned (83)
    Sequence number: 7
    Timestamp: 0
    Synchronization Source identifier: 0x83c117cc (2210469836)
    Payload: afba9b3283c117ccb012ceb683c117ccb0141047

5.3.音量控制

可以使用SET_PARAMETER请求。音量是一个浮点值,表示音频衰减(以分贝为单位)。值为-144表示音频为静音。然后从-30到0。

例子:设置音频音量

客户端→服务器

SET_PARAMETER rtsp://fe80::217:f2ff:fe0f:e0f6/3413821438 RTSP/1.0
CSeq: 6
Session: 1
Content-Type: text/parameters
Content-Length: 20
User-Agent: iTunes/10.6 (Macintosh; Intel Mac OS X 10.7.3) AppleWebKit/535.18.5
Client-Instance: 56B29BB6CB904862
DACP-ID: 56B29BB6CB904862
Active-Remote: 1986535575

volume: -11.123877

服务器→客户端

RTSP/1.0 200 OK
Server: AirTunes/130.14
CSeq: 6

5.4.元数据

当前跟踪的元数据将使用SET_PARAMETER请求。这使苹果电视可以显示轨道名称,艺术家,专辑,封面艺术作品和时间表。这个RTP-Info标头包含rtptime参数,该参数具有对应于元数据有效时间的RTP时间戳。

航迹信息

当前轨道的信息将在DAAP (数字音频接入协议)格式,与application/x-dmap-tagged内容类型

AppleTV上显示了以下DAAP属性:

属性 描述
dmap.itemname 轨道名称
daap.songartist 艺人
daap.songalbum 相册

例子:发送跟踪信息

客户端→服务器

SET_PARAMETER rtsp://fe80::217:f2ff:fe0f:e0f6/3413821438 RTSP/1.0
CSeq: 8
Session: 1
Content-Type: application/x-dmap-tagged
Content-Length: 3242
RTP-Info: rtptime=1146549156
User-Agent: iTunes/10.6 (Macintosh; Intel Mac OS X 10.7.3) AppleWebKit/535.18.5
Client-Instance: 56B29BB6CB904862
DACP-ID: 56B29BB6CB904862
Active-Remote: 1986535575

<DMAP DATA>

服务器→客户端

RTSP/1.0 200 OK
Server: AirTunes/130.14
CSeq: 8

盖艺术品

艺术品作为JPEG图片image/jpeg内容类型

例子:送盖艺术品

客户端→服务器

SET_PARAMETER rtsp://fe80::217:f2ff:fe0f:e0f6/3413821438 RTSP/1.0
CSeq: 9
Session: 1
Content-Type: image/jpeg
Content-Length: 34616
RTP-Info: rtptime=1146549156
User-Agent: iTunes/10.6 (Macintosh; Intel Mac OS X 10.7.3) AppleWebKit/535.18.5
Client-Instance: 56B29BB6CB904862
DACP-ID: 56B29BB6CB904862
Active-Remote: 1986535575

<JPEG DATA>

服务器→客户端

RTSP/1.0 200 OK
Server: AirTunes/130.14
CSeq: 9

回放进度

回放过程发送为text/parameters,带着progress表示三个绝对RTP时间戳值的参数:start/curr/end.

时间戳 描述
start 当前轨道的开始
curr 电流回放位置
end 当前轨道的结束

相对位置和轨道持续时间可计算如下:

例子:发送回放过程

客户端→服务器

SET_PARAMETER rtsp://fe80::217:f2ff:fe0f:e0f6/3413821438 RTSP/1.0
CSeq: 10
Session: 1
Content-Type: text/parameters
Content-Length: 44
User-Agent: iTunes/10.6 (Macintosh; Intel Mac OS X 10.7.3)
AppleWebKit/535.18.5
Client-Instance: 56B29BB6CB904862
DACP-ID: 56B29BB6CB904862
Active-Remote: 1986535575

progress: 1146221540/1146549156/1195701740

服务器→客户端

RTSP/1.0 200 OK
Server: AirTunes/130.14
CSeq: 10

5.5.机场快线认证

向机场快车发送音频数据需要RSA基于身份验证所有二进制数据都使用基准64 (RFC 4648)没有填充物。

客户端

服务器端

客户端

例子:机场快线挑战/回应

客户端→服务器

ANNOUNCE rtsp://10.0.1.101/3172942895 RTSP/1.0
CSeq: 1
Content-Type: application/sdp
Content-Length: 567
User-Agent: iTunes/4.6 (Windows; N)
Client-Instance: 9FF35780A8BC8D2B
Apple-Challenge: 09KF45soMYmvj6dpsUGiIg

v=0
o=iTunes 3172942895 0 IN IP4 10.0.1.101
s=iTunes
c=IN IP4 10.0.1.103
t=0 0
m=audio 0 RTP/AVP 96
a=rtpmap:96 AppleLossless
a=fmtp:96 4096 0 16 40 10 14 2 255 0 0 44100
a=rsaaeskey:5QYIqmdZGTONY5SHjEJrqAhaa0W9wzDC5i6q221mdGZJ5ubO6Kg
            yhC6U83wpY87TFdPRdfPQl2kVC7+Uefmx1bXdIUo07ZcJsqMbgtje4w2JQw0b
            Uw2BlzNPmVGQOxfdpGc3LXZzNE0jI1D4conUEiW6rrzikXBhk7Y/i2naw13ayy
            xaSwtkiJ0ltBQGYGErbV2tx43QSNj7O0JIG9GrF2GZZ6/UHo4VH+ZXgQ4NZvP/
            QXPCsLutZsvusFDzIEq7TN1fveINOiwrzlN+bckEixvhXlvoQTWE2tjbmQYhMvO
            FIly5gNbZiXi0l5AdolX4jDC2vndFHqWDks/3sPikNg
a=aesiv:zcZmAZtqh7uGcEwPXk0QeA

服务器→客户端

RTSP/1.0 200 OK
CSeq: 1
Apple-Response: u+msU8Cc7KBrVPjI/Ir8fOL8+C5D3Jsw1+acaW3MNTndrTQAeb/a
                5m10UVBX6wb/DYQGY+b28ksSwBjN0nFOk4Y2cODEf83FAh7B
                mkLpmpkpplp7zVXQ+Z9DcB6gC60ZsS3t98aoR7tSzVLKZNgi2X2sC+vGsz
                utQxX03HK008VjcdngHv3g1p2knoETd07T6eVfZCmPqp6Ga7Dj8VIIj/GEP3
                AjjDx3lJnQBXUDmxM484YXLXZjWFXCiY8GJt6whjf7/2c3rIoT3Z7PQpEvPmM
                1MXU9cv4NL59Y/q0OAVQ38foOz7eGAhfvjOsCnHU25aik7/7ToIYt1tyVtap/kA
Audio-Jack-Status: connected; type=analog

5.6.遥控

音频扬声器可以向AirPlay客户端发送命令,以更改当前的音轨、暂停和恢复播放、洗牌播放列表等等。的子集DACP (数字音频控制协议)。AirPlay客户端通过包括DACP-ID它的RTSP请求中的标头,带有DACP服务器的64位ID.阿Active-Remote标头也包括在内,用作身份验证令牌。

AirPlay服务器需要浏览mdns_dacp._tcp匹配DACP服务器的服务。服务器名称看起来像iTunes_Ctrl_$ID.

来自iTunes的DACP服务

name: iTunes_Ctrl_56B29BB6CB904862
type: _dacp._tcp
port: 3689
txt:
 txtvers=1
 Ver=131075
 DbId=63B5E5C0C201542E
 OSsi=0x1F5

一旦确定了DACP服务器,就可以将HTTP请求发送到相应的服务端口。这个Active-Remote头必须包含在这些请求中,因此不需要额外的配对。远程控制命令的位置是/ctrl-int/1/$CMD。可以使用下列命令:

命令 描述
beginff 开始快速前进
beginrew 开始倒带
mutetoggle 切换静音状态
nextitem 播放播放列表中的下一项
previtem 播放播放列表中的前一项
pause 暂停回放
playpause 在播放和暂停之间切换
play 开始回放
stop 停止播放
playresume 快进或倒带后弹奏
shuffle_songs 洗牌播放列表
volumedown 把音频音量调小
volumeup 把音频音量调高

例子:发送暂停命令

服务器→客户端

GET /ctrl-int/1/pause HTTP/1.1
Host: starlight.local.
Active-Remote: 1986535575

客户端→服务器

HTTP/1.1 204 No Content
Date: Tue, 06 Mar 2012 16:38:51 GMT
DAAP-Server: iTunes/10.6 (Mac OS X)
Content-Type: application/x-dmap-tagged
Content-Length: 0

6.屏幕镜像

屏幕镜像是通过发送H.264在TCP连接上编码的视频流。这个流是用一个128字节的头来打包的.AAC-ELD音频使用AirTunes协议发送。至于主时钟,则使用NTP.

此外,一旦客户端启动视频播放,就会建立一个标准的AirPlay连接来发送视频URL,并停止镜像。这避免了解码和重新编码视频,这将导致质量损失.

6.1.http请求

屏幕镜像不使用标准AirPlay服务。相反,它连接到一个明显硬编码的端口7100。这是一个HTTP服务器,它支持以下请求:

GET /stream.xml

检索有关服务器功能的信息。服务器发送具有以下属性的XML属性列表:

钥匙 类型 价值 描述
height 整型 720 垂直分辨率
width 整型 1280 水平分辨率
overscanned 布尔型 千真万确 显示器扫描过度了吗?
refreshRate 真品 0.01666… 刷新频率60 Hz(1/60)
version 130.14 服务器版本

这些属性告诉我们,AirPlay服务器连接到1280x720,60 Hz,过扫描显示。

例子:获取镜像服务器信息

客户端→服务器

GET /stream.xml HTTP/1.1
Content-Length: 0

服务器→客户端

HTTP/1.1 200 OK
Date: Mon, 08 Mar 2012 15:30:27 GMT
Content-Type: text/x-apple-plist+xml
Content-Length: 411

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
 <dict>
  <key>height</key>
  <integer>720</integer>
  <key>overscanned</key>
  <true/>
  <key>refreshRate</key>
  <real>0.016666666666666666</real>
  <key>version</key>
  <string>130.14</string>
  <key>width</key>
  <integer>1280</integer>
 </dict>
</plist>

后/流

启动现场视频传输。客户端发送一个二进制属性列表,其中包含有关流的信息,然后紧接流本身。此时,连接不再是有效的HTTP连接。

发送下列参数:

钥匙 类型 价值 描述
设备ID 整型 181221086727016 Mac地址(A4:D1:D2:80:0B:68)
会话ID 整型 –808788724 会话ID(0xcfcadd0c)
版本 130.16 服务器版本
顺1 数据 (72个字节) AES密钥,用FairPlay加密
顺2 数据 (16字节) AES初始化向量
晚发型 整型 90 视频延迟(Ms)
fpsInfo 列阵
时间戳信息 列阵

这个param1param2参数是可选的。

一旦服务器收到/stream请求时,它会将NTP请求发送到端口7010上的客户端,这似乎也是硬编码的。客户端需要将其主时钟导出到那里,该时钟将用于音频/视频同步和时钟恢复。

例子:发送流信息

客户端→服务器

POST /stream HTTP/1.1
X-Apple-Device-ID: 0xa4d1d2800b68
Content-Length: 503

<BINARY PLIST DATA>

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
 <dict>
  <key>deviceID</key>
  <integer>181221086727016</integer>
  <key>fpsInfo</key>
  <array>
   <dict> <key>name</key> <string>SubS</string> </dict>
   <dict> <key>name</key> <string>B4En</string> </dict>
   <dict> <key>name</key> <string>EnDp</string> </dict>
   <dict> <key>name</key> <string>IdEn</string> </dict>
   <dict> <key>name</key> <string>IdDp</string> </dict>
   <dict> <key>name</key> <string>EQDp</string> </dict>
   <dict> <key>name</key> <string>QueF</string> </dict>
   <dict> <key>name</key> <string>Sent</string> </dict>
  </array>
  <key>latencyMs</key>
  <integer>90</integer>
  <key>param1</key>
  <data>
  RlBMWQECAQAAAAA8AAAAANvKuDizduszL1hG9IvIk+AAAAAQukdPJ5Jw/gGBAl22WZdF
  m9ujZEGIV7jm3ZByWm51HjpDwjYY
  </data>
  <key>param2</key>
  <data>
  3qpOHtYWbBPyEWPnGt1BuQ==
  </data>
  <key>sessionID</key>
  <integer>-808788724</integer>
  <key>timestampInfo</key>
  <array>
   <dict> <key>name</key> <string>SubSu</string> </dict>
   <dict> <key>name</key> <string>BePxT</string> </dict>
   <dict> <key>name</key> <string>AfPxT</string> </dict>
   <dict> <key>name</key> <string>BefEn</string> </dict>
   <dict> <key>name</key> <string>EmEnc</string> </dict>
   <dict> <key>name</key> <string>QueFr</string> </dict>
   <dict> <key>name</key> <string>SndFr</string> </dict>
  </array>
  <key>version</key>
  <string>130.16</string>
 </dict>
</plist>

6.2.流分组

视频流使用128个字节头进行分组,然后是一个可选的有效载荷.似乎只使用了头的前64个字节。标题以以下小Endian字段开头:

大小 描述
4字节 有效载荷大小
2字节 有效载荷类型
2字节 0x1e如果类型=2,否则6
8个字节 NTP时间戳

有三种类型的数据包:

类型 描述
0 视频流
1 编解码器数据
2 心跳

编解码器数据

此数据包包含H.264中的额外数据avcC格式(ISO/IEC 14496:15)。它是在流的开头发送的,每次视频属性可能会改变,当屏幕方向改变,屏幕打开或关闭时。

H.264来自iPad的编解码数据

0000   01 64 c0 28 ff e1 00 10 67 64 c0 28 ac 56 20 0d
0010   81 4f e5 9b 81 01 01 01 01 00 04 28 ee 3c b0

H.264编解码器数据解释如下:

大小 价值 描述
1字节 1 版本
1字节 100 概况(高)
1字节 0xc0 兼容性
1字节 40 级别(4.0)
6位 0x3f 预留
2位 3 Nal单位长度大小-1
3位 0x7 预留
5位 1 SPS数
2字节 16 SPS长度
16个字节 序列参数集
1字节 1 PPS数目
2字节 4 PPS长度
4字节 图像参数集

来自iPad的编解码数据包

0000   1f 00 00 00 01 00 06 00 1d 9a 9f 59 ef de 00 00
0010   00 00 58 44 00 00 22 44 00 00 00 00 00 00 00 00
0020   00 00 00 00 00 00 00 00 00 00 58 44 00 00 22 44
0030   00 00 50 43 00 00 10 42 00 c0 57 44 00 c0 21 44
0040   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0050   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0060   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0070   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0080   01 64 c0 28 ff e1 00 10 67 64 c0 28 ac 56 20 0d
0090   81 4f e5 9b 81 01 01 01 01 00 04 28 ee 3c b0

视频比特流

此数据包包含要解码的视频比特流。有效载荷可以可选地加密AES。在报头中找到的NTP时间戳用作表示时间戳。

来自iPad的视频比特流包

0000   c8 08 00 00 00 00 06 00 e9 e6 f5 ac 60 e0 00 00
0010   58 37 6e f9 40 01 00 00 00 00 00 00 00 00 00 00
0020   00 00 00 00 00 00 00 00 00 00 58 44 00 00 22 44
0030   00 00 50 43 00 00 10 42 00 c0 57 44 00 c0 21 44
0040   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0050   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0060   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0070   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0080   ...

心跳

每秒钟发送一次,此数据包不包含任何有效负载。

来自iPad的心跳包

0000   00 00 00 00 02 00 1e 00 00 00 00 00 00 00 00 00
0010   4d d8 1a 41 00 00 00 00 00 00 20 41 86 c9 e2 36
0020   00 00 00 00 80 88 44 4b 00 00 00 00 00 00 00 00
0030   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0040   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0050   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0060   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0070   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

6.3.时间同步

时间同步在UDP端口7010(客户端)和7011(服务器)上进行,使用NTP议定书(RFC 5905)。AirPlay服务器运行NTP客户端。请求以3秒钟的间隔发送给AirPlay客户端。时间戳的引用日期是镜像会话的开始。

服务器→客户端

0000   23 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0010   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0020   00 00 00 00 00 00 00 00 00 00 01 c4 c8 ac 5d b5

Network Time Protocol
    Flags: 0x23
        00.. .... = Leap Indicator: no warning (0)
        ..10 0... = Version number: NTP Version 4 (4)
        .... .011 = Mode: client (3)
    Peer Clock Stratum: unspecified or invalid (0)
    Peer Polling Interval: invalid (0)
    Peer Clock Precision: 1.000000 sec
    Root Delay: 0.0000 sec
    Root Dispersion: 0.0000 sec
    Reference ID: NULL
    Reference Timestamp: Jan 1, 1970 00:00:00.000000000 UTC
    Origin Timestamp: Jan 1, 1970 00:00:00.000000000 UTC
    Receive Timestamp: Jan 1, 1970 00:00:00.000000000 UTC
    Transmit Timestamp: Jan 1, 1900 00:07:32.783880000 UTC

客户端→服务器

0000   24 01 02 e8 00 00 00 00 00 00 00 00 41 49 52 50
0010   00 00 00 00 00 00 00 00 00 00 01 c4 c8 ac 5d b5
0020   00 00 01 c4 c9 6a 0b a1 00 00 01 c4 c9 78 73 d2

Network Time Protocol
    Flags: 0x24
        00.. .... = Leap Indicator: no warning (0)
        ..10 0... = Version number: NTP Version 4 (4)
        .... .100 = Mode: server (4)
    Peer Clock Stratum: primary reference (1)
    Peer Polling Interval: invalid (2)
    Peer Clock Precision: 0.000000 sec
    Root Delay: 0.0000 sec
    Root Dispersion: 0.0000 sec
    Reference ID: Unidentified reference source 'AIRP'
    Reference Timestamp: Jan 1, 1970 00:00:00.000000000 UTC
    Origin Timestamp: Jan 1, 1900 00:07:32.783880000 UTC
    Receive Timestamp: Jan 1, 1900 00:07:32.786774000 UTC
    Transmit Timestamp: Jan 1, 1900 00:07:32.786994000 UTC

7.密码保护

AirPlay服务器可以要求一个密码来显示来自网络的任何内容。这是使用标准实现的。http摘要认证 (RFC 2617),用于AirTunes的RTSP,以及用于其他一切的HTTP。AppleTV接受的摘要域和用户名如下:

服务 境界 用户名
AirTunes raop iTunes
空中播放 AirPlay AirPlay

例1:AirTunes密码请求

客户端→服务器

ANNOUNCE rtsp://fe80::217:f2ff:fe0f:e0f6/3414156527 RTSP/1.0
CSeq: 3
Content-Type: application/sdp
Content-Length: 348
User-Agent: iTunes/10.6 (Macintosh; Intel Mac OS X 10.7.3) AppleWebKit/535.18.5
Client-Instance: 56B29BB6CB904862
DACP-ID: 56B29BB6CB904862
Active-Remote: 448488758

<SDP DATA>

服务器→客户端

RTSP/1.0 401 Unauthorized
Server: AirTunes/130.14
WWW-Authenticate: Digest realm="raop", nonce="ddfd59b4aea7bbbcbbb3b60d3b2768b7"
CSeq: 3

客户端→服务器

ANNOUNCE rtsp://fe80::217:f2ff:fe0f:e0f6/3414156527 RTSP/1.0
CSeq: 4
Content-Type: application/sdp
Content-Length: 348
User-Agent: iTunes/10.6 (Macintosh; Intel Mac OS X 10.7.3) AppleWebKit/535.18.5
Client-Instance: 56B29BB6CB904862
DACP-ID: 56B29BB6CB904862
Active-Remote: 448488758
Authorization: Digest username="iTunes", realm="raop", nonce="ddfd59b4aea7bbbcbbb3b60d3b2768b7", uri="rtsp://fe80::217:f2ff:fe0f:e0f6/3414156527", response="36f93a97c9038598290729ec0f141b03"

<SDP DATA>

服务器→客户端

RTSP/1.0 200 OK
Server: AirTunes/130.14
CSeq: 4

例2:空中播放密码请求

客户端→服务器

POST /play HTTP/1.1
User-Agent: iTunes/10.6 (Macintosh; Intel Mac OS X 10.7.3) AppleWebKit/535.18.5
Content-Length: 163
Content-Type: text/parameters

Content-Location: http://192.168.1.18:3689/airplay.mp4?database-spec='dmap.persistentid:0x63b5e5c0c201542e'&item-spec='dmap.itemid:0x21e'
Start-Position: 0.317546

服务器→客户端

HTTP/1.1 401 Unauthorized
Date: Fri, 09 Mar 2012 15:50:40 GMT
Content-Length: 0
WWW-Authenticate: Digest realm="AirPlay", nonce="MTMzMTMwODI0MCDEJP5Jo7HFo81rbAcKNKw2"

客户端→服务器

POST /play HTTP/1.1
User-Agent: iTunes/10.6 (Macintosh; Intel Mac OS X 10.7.3) AppleWebKit/535.18.5
Content-Length: 163
Content-Type: text/parameters
Authorization: Digest username="AirPlay", realm="AirPlay", nonce="MTMzMTMwODI0MCDEJP5Jo7HFo81rbAcKNKw2", uri="/play", response="aa085eea3e66a2e56125a4957e70894a"

Content-Location: http://192.168.1.18:3689/airplay.mp4?database-spec='dmap.persistentid:0x63b5e5c0c201542e'&item-spec='dmap.itemid:0x21e'
Start-Position: 0.317546

服务器→客户端

HTTP/1.1 200 OK
Date: Fri, 09 Mar 2012 15:50:40 GMT
Content-Length: 0

8.历史

日期 变化
2012–03–20 初版。

9.资源

9.1.IETF RFCS

9.2.IETF草案

9.3.Apple协议