AirPlay协议规范(非官方)
1. 简介
AirPlay是Apple实现的一系列协议,用于在Apple TV上观看或收听来自iOS设备或iTunes中的各种类型的媒体内容。 在本文档中,“iOS设备”是指iPhone,iPod touch或iPad。AirPlay支持以下场景:
显示来自iOS设备的照片和幻灯片。
接收来自iOS设备或iTunes的音频流。
显示来自iOS设备或iTunes的视频。
显示来自iOS设备或OS X Mountain Lion的屏幕内容,称为AirPlay镜像。 它要求硬件能够在不占用过多CPU的情况下对实时视频进行编码,因此仅在iPhone 4S、iPad 2、新iPad和具有Sandy Bridge CPU的Mac上使用。
音频流也可以从iOS设备或iTunes流向AirPort Express基站或支持AirPlay的第三方音频设备。 最初称为AirTunes,但后来在添加了对Apple TV的视频支持后,Apple将其重命名为AirPlay。
本文档介绍的这些协议,已用于Apple TV 5.0、iOS 5.1和iTunes 10.6。这些协议基于众所周知的标准网络协议, 例如多播DNS、HTTP、RTSP、RTP和NTP,并对其进行了扩展。
文档中的所有内容都是通过各种反向工程技术收集的,因此有些可能不准确和不完整。此外,本文档没有说明如何规避Apple实施的任何类型的安全性:
不提供任何RSA密钥。
没有说明如何解码受FairPlay DRM 保护的iTunes视频。
没有对FairPlay身份验证(SAPv2.5)进行说明,iOS设备和OS X Mountain Lion用其保护音频和屏幕内容。
请不要给我发电子邮件,我不会回复。实际上,要在Apple TV上观看媒体内容,并不需要了解所有内容。
2. 服务发现
AirPlay使用了基于DNS的服务发现 (基于多播DNS,又名Bonjour), 因此不需要任何配置就能在网络上找到兼容的设备。
AirPlay设备(如Apple TV)发布两项服务。第一个是用于音频流传输的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 |
false | 接收端是否需要密码? |
sr |
44100 | 音频采样频率:44100 Hz |
ss |
16 | 音频采样大小:16位 |
tp |
UDP | 支持的传输层协议:TCP或UDP |
vs |
130.14 | 服务器端版本:130.14 |
am |
AppleTV2,1 | 设备型号 |
音频编解码器
cn | 描述 |
---|---|
0 | PCM |
1 | Apple无损(ALAC) |
2 | AAC |
3 | AAC ELD(增强型低延迟) |
加密方式
et | 描述 |
---|---|
0 | 未加密 |
1 | RSA (AirPort Express) |
3 | FairPlay |
4 | MFiSAP(第三方设备) |
5 | FairPlay SAPv2.5 |
元数据类型
md | 描述 |
---|---|
0 | 文本 |
1 | 插图(artwork) |
2 | 播放进度(progress) |
2.2. AirPlay服务
AirPlay服务
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 | 支持的功能的位域(bitfield) |
pw |
1 | 服务器受密码保护 |
仅当AirPlay服务器受密码保护时,才显示pw
字段。否则,它不包括在TXT记录中。
features
字段的位域(bitfield)定义如下:
位 | 名称 | 描述 |
---|---|---|
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 |
支持FairPlay安全身份验证 |
13 | PhotoCaching |
支持照片预加载 |
请注意,Apple TV不支持VideoVolumeControl
。可能会用在未来的Apple电视上。
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
标头用于把此连接链接到另一个(而非反向)
(link this connection to the other (non-reverse) one)。 事件通过POST
请求来发送,内容为XML属性表,
地址为/event
。
3. 照片
照片是JPEG数据,通过PUT
请求传输到AirPlay服务器。它们可以立即显示,也可以缓存以备将来使用。
3.1. HTTP请求
GET /slideshow-features
客户端可以获取幻灯片显示的转场列表。可以让用户在开始幻灯片放映之前选择一个。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>
PUT /photo
向服务器发送一张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: 使用溶解(Dissolve)转场显示图片
客户端 → 服务器
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
PUT /slideshows/1
开始或停止一个幻灯片放映会话。开始时,将传输幻灯片设置,例如幻灯片持续时间和选定的转场方式。以下参数在XML属性列表中发送:
键 | 类型 | 描述 |
---|---|---|
settings.slideDuration | integer | 幻灯片持续时间(以秒为单位) |
settings.theme | string | 转场方式 |
state | string | 播放 还是停止 |
示例:发送幻灯片设置
客户端 → 服务器
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
停止一个照片或幻灯片会话。
客户端 → 服务器
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)
此事件通知客户端照片会话已结束。然后,服务器安全地断开连接。
键 | 类型 | 描述 |
---|---|---|
category | string | photo |
sessionID | integer | 会话ID |
state | string | 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)
此事件通知服务器当前的播放状态。(译注:怀疑作者笔误,应是向客户端通知)
键 | 类型 | 描述 |
---|---|---|
category | string | slideshow |
lastAssetID | integer | 最后一张照片(Asset)ID |
sessionID | integer | 会话ID |
state | string | loading , playing 还是stopped |
示例: 当前正在播放幻灯片
服务器 → 客户端
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
。
向/slideshows/1/assets/1
地址发送GET
请求,以从AirPlay客户端获取新图片。期望得到带有以下参数的二进制属性列表:
键 | 类型 | 描述 |
---|---|---|
data | data | JPEG图片 |
info.id | integer | 资产ID |
info.key | integer | 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请求
GET /server-info
获取有关AirPlay服务器的常规信息。这些信息以XML属性列表形式返回:
键 | 类型 | 值 | 描述 |
---|---|---|---|
deviceid | string | 58:55:CA:1A:E2:88 | MAC地址 |
features | integer | 14839 | 0x39f7 |
model | string | AppleTV2,1 | 设备型号 |
protovers | string | 1.0 | 协议版本 |
srcvers | string | 120.2 | 服务器版本 |
model
、deviceid
、srcvers
和features
属性和通过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>
POST /play
开始播放视频。Body包含以下参数:
名称 | 类型 | 描述 |
---|---|---|
Content-Location |
URL | 影片的URL |
Start-Position |
float | 起始位置介于0和1之间 |
支持渐进式下载MP4电影。 如VideoHTTPLiveStreams
功能标志所示,
也可能支持HTTP Live Streaming。
介于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
POST /scrub
定位到视频中的任意位置。该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
POST /rate
更改播放速率。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
停止播放。
示例:停止播放
客户端 → 服务器
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
GET /scrub
获取当前播放位置。可以重复调来更新客户端上的进度条。返回以下参数:
名称 | 类型 | 描述 |
---|---|---|
duration |
float | 时长(秒) |
position |
float | 位置(秒) |
示例:获取当前播放进度
客户端 → 服务器
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
GET /playback-info
获取播放信息,例如位置、时长、速率、缓冲状态等。返回带有以下参数的XML属性列表:
键 | 类型 | 描述 |
---|---|---|
duration |
real | 播放时长(秒) |
position |
real | 播放位置(秒) |
rate |
real | 播放速率 |
readyToPlay |
boolean | 准备播放 |
playbackBufferEmpty |
boolean | 缓冲区为空 |
playbackBufferFull |
boolean | 缓冲区已满 |
playbackLikelyToKeepUp |
boolean | 缓冲数据是否跟的上播放(playback likely to keep up) |
loadedTimeRanges |
array | 加载时间范围/td> |
seekableTimeRanges |
array | 可定位的时间范围 |
范围定义为包含以下键字典:
键 | 类型 | 描述 |
---|---|---|
start |
real | 范围的开始时长(秒) |
duration |
real | 范围的时长(秒) |
示例: 获取播放信息
客户端 → 服务器
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>
GET /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. 事件
用于将播放状态发送到客户端:
键 | 类型 | 描述 |
---|---|---|
category | string | video |
sessionID | integer | 会话ID |
state | string | loading , playing , paused 或stopped |
示例:通知客户端视频播放已暂停
服务器 → 客户端
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. Audio
Audio streaming is supported using the RTSP protocol (RFC 2326).
5.1. RTSP requests
OPTIONS
The OPTIONS
request asks the RTSP server for its supported methods.
Apple TV supports the following methods: ANNOUNCE
, SETUP
, RECORD
,
PAUSE
, FLUSH
, TEARDOWN
, OPTIONS
, GET_PARAMETER
, SET_PARAMETER
,
POST
and GET
.
client → server
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
server → client
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
The ANNOUNCE
request tells the RTSP server about stream properties using
SDP (RFC 4566). Codec informations and encryption keys are of particular
interest.
Example 1: ANNOUNCE
for Apple Lossless audio from iTunes
client → server
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
server → client
RTSP/1.0 200 OK
Server: AirTunes/130.14
CSeq: 3
Example 2: ANNOUNCE
for AAC audio from an iOS device
client → server
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
server → client
RTSP/1.0 200 OK
Server: AirTunes/130.14
CSeq: 16
Example 3: ANNOUNCE
for AAC-ELD audio and H.264 video from an iOS device
client → server
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
server → client
RTSP/1.0 200 OK
Server: AirTunes/130.14
CSeq: 27
SETUP
The SETUP
request initializes a record session. It sends all the
necessary transport informations. Three UDP channels are setup:
channel | description |
---|---|
server | audio data |
control | sync and retransmit requests |
timing | master clock sync |
Example: setup a record session
client → server
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
server → client
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
The RECORD
request starts the audio streaming. The RTP-Info
header
contains the following parameters:
name | size | description |
---|---|---|
seq |
16-bit | initial RTP sequence number |
rtptime |
32-bit | initial RTP timestamp |
Example: start audio stream
client → server
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
server → client
RTSP/1.0 200 OK
Audio-Latency: 2205
Server: AirTunes/130.14
CSeq: 5
FLUSH
The FLUSH
request stops the streaming.
Example: pause the audio stream
client → server
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
server → client
RTSP/1.0 200 OK
RTP-Info: rtptime=1147914212
Server: AirTunes/130.14
CSeq: 31
TEARDOWN
The TEARDOWN
request ends the RTSP session.
Example: close session 1
client → server
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
server → client
RTSP/1.0 200 OK
Server: AirTunes/130.14
CSeq: 32
5.2. RTP Streams
Audio packets are fully RTP compliant. Control and timing packets, however, do not seem to be fully compliant with the RTP standard.
The following payload types are defined:
payload type | port | description |
---|---|---|
82 | timing_port |
timing request |
83 | timing_port |
timing reply |
84 | control_port |
time sync |
85 | control_port |
retransmit request |
86 | control_port |
retransmit reply |
96 | server_port |
audio data |
Audio packets
Audio data is sent using the DynamicRTP-Type-96
payload type. The
Marker
bit is set on the first packet sent after RECORD
or FLUSH
requests. The RTP payload contains optionally encrypted audio data.
Example: encrypted audio packet
client → server
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...
Sync packets
Sync packets are sent once per second to the control port. They are used to
correlate the RTP timestamps currently used in the audio stream to the NTP time
used for clock synchronization. Payload type is 84, the Marker
bit is always
set and the Extension
bit is set on the first packet after RECORD
or
FLUSH
requests. The SSRC
field is not included in the RTP header.
bytes | description |
---|---|
8 | RTP header without SSRC |
8 | current NTP time |
4 | RTP timestamp for the next audio packet |
Example: sync packet
client → server
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
Retransmit packets
AirTunes supports resending audio packets which have been lost. Payload
type is 85 for retransmit queries, the Marker
bit is always set and the
SSRC
field is not included in the RTP header.
bytes | description |
---|---|
8 | RTP header without SSRC |
2 | sequence number for the first lost packet |
2 | number of lost packets |
Retransmit replies have payload type 86, with a full audio RTP packet after the sequence number.
Timing packets
Timing packets are used to synchronize a master clock for audio. This is useful for clock recovery and precise synchronization of several devices playing the same audio stream.
Timing packets are sent at 3 second intervals. They always have the
Marker
bit set, and payload type 82 for queries and 83 for replies.
The SSRC
field is not included in the RTP header, so it takes only 8
bytes, followed by three NTP timestamps:
bytes | description |
---|---|
8 | RTP header without SSRC |
8 | origin timestamp |
8 | receive timestamp |
8 | transmit timestamp |
Example: timing query/reply
server → client
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
client → server
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. Volume Control
Audio volume can be changed using a SET_PARAMETER
request. The volume
is a float value representing the audio attenuation in dB. A value of
–144 means the audio is muted. Then it goes from –30 to 0.
Example: set audio volume
client → server
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
server → client
RTSP/1.0 200 OK
Server: AirTunes/130.14
CSeq: 6
5.4. Metadata
Metadata for the current track are sent using SET_PARAMETER
requests.
This allows the Apple TV to show the track name, artist, album, cover
artwork and timeline. The RTP-Info
header contains a rtptime
parameter
with the RTP timestamp corresponding to the time from which the metadata
is valid.
Track Informations
Informations about the current track are sent in the DAAP (Digital
Audio Access Protocol) format, with application/x-dmap-tagged
content
type.
The following DAAP attributes are displayed on Apple TV:
attribute | description |
---|---|
dmap.itemname |
track name |
daap.songartist |
artist |
daap.songalbum |
album |
Example: send track informations
client → server
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>
server → client
RTSP/1.0 200 OK
Server: AirTunes/130.14
CSeq: 8
Cover Artwork
Artworks are sent as JPEG pictures, with image/jpeg
content type.
Example: send cover artwork
client → server
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>
server → client
RTSP/1.0 200 OK
Server: AirTunes/130.14
CSeq: 9
Playback Progress
Playback progress is sent as text/parameters
, with a progress
parameter representing three absolute RTP timestamps values:
start
/curr
/end
.
timestamp | description |
---|---|
start |
beginning of the current track |
curr |
current playback position |
end |
end of the current track |
The relative position and track duration can be computed as follows:
position = rtptime_to_sec(curr - start)
duration = rtptime_to_sec(end - start)
Example: send playback progress
client → server
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
server → client
RTSP/1.0 200 OK
Server: AirTunes/130.14
CSeq: 10
5.5. AirPort Express Authentication
Sending audio data to the AirPort Express requires a RSA based authentication. All binary data are encoded using Base64 (RFC 4648) without padding.
Client side
In the
ANNOUNCE
request, the client sends a 128-bit random number in theApple-Challenge
header.A 128-bit AES key is generated, encrypted with the RSA public key using the OAEP encryption scheme, and sent along with an initialization vector in the
rsaaeskey
andaesiv
SDP attributes.
Server side
The AirPort Express decrypts the AES key with its RSA private key, it will be used to decrypt the audio payload.
The AirPort Express signs the
Apple-Challenge
number with its RSA private key using the PKCS#1 signature scheme and send the result in theApple-Response
header.
Client side
- The client decrypts the
Apple-Response
value with the RSA public key, and checks that it is the same random number it has previously generated.
Example: AirPort Express challenge/response
client → server
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
server → client
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. Remote Control
Audio speakers can send commands to the AirPlay client to change the
current track, pause and resume playback, shuffle the playlist, and
more. This uses a subset of DACP (Digital Audio Control Protocol).
An AirPlay client advertises this capability by including a DACP-ID
header in its RTSP requests, with a 64-bit ID for the DACP server. An
Active-Remote
header is included as well, serving as an authentication
token.
The AirPlay server needs to browse the mDNS _dacp._tcp
services for a
matching DACP server. Server names look like iTunes_Ctrl_$ID
.
DACP service from iTunes
name: iTunes_Ctrl_56B29BB6CB904862
type: _dacp._tcp
port: 3689
txt:
txtvers=1
Ver=131075
DbId=63B5E5C0C201542E
OSsi=0x1F5
Once the DACP server has been identified, HTTP requests can be sent to the
corresponding service port. The Active-Remote
header must be included in
these requests, so no additional pairing is required. The location for
remote control commands is /ctrl-int/1/$CMD
. The following commands are
available:
command | description |
---|---|
beginff |
begin fast forward |
beginrew |
begin rewind |
mutetoggle |
toggle mute status |
nextitem |
play next item in playlist |
previtem |
play previous item in playlist |
pause |
pause playback |
playpause |
toggle between play and pause |
play |
start playback |
stop |
stop playback |
playresume |
play after fast forward or rewind |
shuffle_songs |
shuffle playlist |
volumedown |
turn audio volume down |
volumeup |
turn audio volume up |
Example: send a pause command
server → client
GET /ctrl-int/1/pause HTTP/1.1
Host: starlight.local.
Active-Remote: 1986535575
client → server
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. 屏幕镜像
通过在TCP连接上传输H.264编码的视频流来实现屏幕镜像。该流使用128字节的标头打包。使用AirTunes协议发送AAC-ELD音频。 至于主时钟,它使用NTP同步。
此外,客户端一旦开始视频播放,就会建立标准的AirPlay连接来发送视频URL,同时镜像也会停止。这样可以避免对视频进行解码和重新编码,否则会导致质量下降。
6.1. HTTP请求
屏幕镜像不使用标准的AirPlay服务。相反,它连接到硬编码的端口7100。这是一个HTTP服务器,支持以下请求:
GET /stream.xml
获取有关服务器支持的功能。服务器发送具有以下属性的XML属性列表:
键 | 类型 | 值 | 描述 |
---|---|---|---|
height |
integer | 720 | 垂直分辨率 |
width |
integer | 1280 | 水平分辨率 |
overscanned |
boolean | true | 是否过扫描显示?(is the display overscanned?) |
refreshRate |
real | 0.01666… | 刷新频率60 Hz (1/60) |
version |
string | 130.14 | 服务器版本 |
这些属性告诉我们,AirPlay服务器提供1280x720、60Hz的过扫描显示。
示例: 获取镜像服务器信息
客户端 → 服务器
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>
POST /stream
开始实时视频传输。客户端发送带有关于流的信息的二进制属性列表,紧随其后的是流本身。此后,该连接不再是有效的HTTP连接。
发送以下参数:
键 | 类型 | 值 | 描述 |
---|---|---|---|
deviceID | integer | 181221086727016 | MAC地址(A4:D1:D2:80:0B:68) |
sessionID | integer | –808788724 | 会话ID(0xcfcadd0c) |
version | string | 130.16 | 服务器版本 |
param1 | data | (72 bytes) | AES密钥,使用FairPlay加密 |
param2 | data | (16 bytes) | AES初始化向量 |
latencyMs | integer | 90 | 视频延迟(毫秒) |
fpsInfo | array | ||
timestampInfo | array |
param1
和param2
是可选的。
服务器一接收到/stream
请求,就会向端口为7010上的客户端发送NTP请求,该端口号似乎也进行了硬编码。
客户端需要在此导出其主时钟,该主时钟将用于音频/视频同步和时钟恢复。
示例: 发送流信息
客户端 → 服务器
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个字节。标头从以下小尾(little-endian)字段开始:
尺寸 | 描述 |
---|---|
4 bytes | 有效载荷大小 |
2 bytes | 有效载荷类型 |
2 bytes | 如果类型= 2,则为0x1e,否则为6 |
8 bytes | NTP时间戳 |
数据包有3种类型:
类型 | 描述 |
---|---|
0 | 视频比特流 |
1 | 编解码器数据 |
2 | 心跳 |
编解码器数据
该数据包包含avcC格式(ISO/IEC 14496:15)的H.264额外数据。它在以下情况下发送:流的开始,每次视频属性可能更改,屏幕方向更改以及屏幕打开或关闭时。
来自iPad的H.264编解码器数据
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 byte | 1 | 版本 |
1 byte | 100 | profile (high) |
1 byte | 0xc0 | 兼容性 |
1 byte | 40 | level (4.0) |
6 bits | 0x3f | 保留 |
2 bits | 3 | NAL单位长度大小-1 |
3 bits | 0x7 | 保留 |
5 bits | 1 | SPS数量 |
2 bytes | 16 | SPS的长度 |
16 bytes | … | 序列参数集(Sequence parameter set) |
1 byte | 1 | PPS数量 |
2 bytes | 4 | PPS长度 |
4 bytes | … | 图片参数集(Picture parameter set) |
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时间戳用作显示(presentation)时间戳。
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. 时间同步
使用NTP协议(RFC 5905)在UDP端口7010(客户端)和7011(服务器)上进行时间同步。 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. Password Protection
An AirPlay server can require a password for displaying any content from the network. This is implemented using standard HTTP Digest Authentication (RFC 2617), over RTSP for AirTunes, and HTTP for everything else. The digest realms and usernames accepted by Apple TV are the following:
service | realm | username |
---|---|---|
AirTunes | raop |
iTunes |
AirPlay | AirPlay |
AirPlay |
Example 1: AirTunes password request
client → server
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>
server → client
RTSP/1.0 401 Unauthorized
Server: AirTunes/130.14
WWW-Authenticate: Digest realm="raop", nonce="ddfd59b4aea7bbbcbbb3b60d3b2768b7"
CSeq: 3
client → server
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>
server → client
RTSP/1.0 200 OK
Server: AirTunes/130.14
CSeq: 4
Example 2: AirPlay password request
client → server
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
server → client
HTTP/1.1 401 Unauthorized
Date: Fri, 09 Mar 2012 15:50:40 GMT
Content-Length: 0
WWW-Authenticate: Digest realm="AirPlay", nonce="MTMzMTMwODI0MCDEJP5Jo7HFo81rbAcKNKw2"
client → server
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
server → client
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 RFC
- RFC 2616: 超文本传输协议– HTTP / 1.1
- RFC 2617: HTTP身份验证:基本和摘要访问身份验证(Basic and Digest Access Authentication)
- RFC 2326: 实时流协议(RTSP)
- RFC 4566: SDP:会话描述协议
- RFC 3550: RTP:用于实时应用程序的传输协议
- RFC 5905: 网络时间协议版本4
- RFC 4648: Base16,Base32和Base64数据编码