关于airplay协议实现镜像功能研究

工作中需要研究airplay以实现IOS的镜像服务端,将了解到的内容记录下来。

 

Airplay可以实现将设备中音频、视频、图像通过本地无线网络发送远端设备;Airplay功能实现利用了很多标准协议,包括multicast DNS,HTTP,RTSP,RTP,RAOP,NTP,见下表1

AirPlay Technology

Display photos and slideshows

Stream audio

Stream video

Display mirroring

Commonly Know as

-

AirPlay, AirTunes

AirPlay

AirPlay Mirroring

Used Protocols, Technology

HTTP

RAOP, RTSP, RTP

HTTP

HTTP, NTP

 

Bonjour是苹果为基于组播域名服务(multicast DNS)的开放性零设置网络标准所起的名字。使用Bonjour的设备在网络中自动传播它们自己的服务信息并聆听其它设备的服务信息,设备之间就象在打招呼,这也是命名为Bonjour(法语:你好)的原因

 

 

ios手机接入wifi后用wireshark抓包能够看到192.168.1.100 向 224.0.0.251 port 5353 发送广播.

 关于airplay协议实现镜像功能研究_第1张图片


 

操作手机,打开媒体播放器时,ios会用MDNS发送Queries,其中有两项服务_raop._tcp.local_airplay._tcp.local,如下图:

 关于airplay协议实现镜像功能研究_第2张图片

 

 

AirplayBonjour做设备发现,在windows中安装BonjourSDKforWin,在任务管理器中有mDNSResponder.exe进程用于mdns协议处理。

 关于airplay协议实现镜像功能研究_第3张图片

 

----------------------------------------------------------------------------------

BonjourSDK Demo

 

BonjourSDK文件夹中Samples目录是一个示例工程,将该工程编译运行,进行测试并对MDNS抓包分析如下:

dns-sd.exe -I   (Test registering and then immediately updating TXT record)

 关于airplay协议实现镜像功能研究_第4张图片

 

pid_t pid = getpid();/*current process id*/
Opaque16 registerPort = { { pid >> 8, pid & 0xFF } };
static const char TXT[] = "\x09" "Test Data";
printf("Registering Service Test._testtxt._tcp.local.\n");
err = DNSServiceRegister(&client, 0, opinterface /*kDNSServiceInterfaceIndexAny*/, "Test", "_testtxt._tcp.", "", NULL, registerPort.NotAnInteger, 0, NULL, reg_reply, NULL); 
if (!err) err = DNSServiceUpdateRecord(client, NULL, 0, sizeof(TXT)-1, TXT, 0);
break;

上面这段代码在 mDns 中注册一个服务,对应在 MDNS 数据包中会有一个 Query Authoritative DNSServiceRegister函数的第三个参数为kDNSServiceInterfaceIndexAny指定Query中Type=ANY,第四个参数是服务名称、第五个参数是支持协议名称,第四、五个参数组合成Name,服务端口号为registerPort,在这个DEMO中是该进程ID(7948),如下如所示:

 关于airplay协议实现镜像功能研究_第5张图片

 

由于上面有query Test._Testtxt._tcp.local,那么mDNS正常对这个query进行应答,由于在query指定TYPE=ANY,所以Answers中除了Test._testtxt.tcp.local外,还有其它服务信息。

DEMO程序中DNSServiceUpdateRecord用于更新TXT文本,如下图所示,在Answers中的TXT字段信息中TXT内容为DEMO程序中所设置的“Test Data”。

 关于airplay协议实现镜像功能研究_第6张图片

 

 

 

----------------------------------------------------------------------------------

Airplayer

 

在网上找到一款可以在windows使用的Airplay服务端(AirPlayer),当然首先需要安装Bonjour,AirPlayer可以实现将ios音频、图像同步在pc端播放,也可以将ios屏幕镜像到pc,我使用wireshark抓包情况如下:

 

1.Airplayer程序启动后,首先向mDNS注册了两个服务,分别支持两个不同的协议_airplay_raop_airplay协议用于视频传输,_raop用于音频流传输(可参考表1)。

 关于airplay协议实现镜像功能研究_第7张图片

 

2.接下来Airplayer程序会针对_airplay_raop这两个服务Answers进行服务描述。

  iTools[CMCC-BAIJIE]._airplay._tcp.local描述airplay协议服务端口为648850C54A5569D80@iTools[CMCC-BAIJIE]._raop._tcp.local描述raop协议服务端口为64886

  重点在于两个服务分别对TXT的描述部份,如下图:

 关于airplay协议实现镜像功能研究_第8张图片

 

协议TXT描述内容必需按Airplay协议标准要求进行描述,该标准在网上未能找到官方文档,但有一个非官方资料可供参考,地址如下:

http://nto.github.io/AirPlay.html

 

我们以_airplay协议TXT描述内容为例,对照Airplay.html文档来看应该不难理解吧..

iTools[CMCC-BAIJIE]._airplay._tcp.local: type TXT, class IN, cache flush

deviceid=0c:54:a5:56:9d:80

features=0x100029FF

flags=0x4

model=AppleTV3,1

srcvers=150.33

vv=1

 

Airplay.html文档中内容描述如下:

AirPlay service

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

The following fields are available in the TXT record:

name

value

description

model

AppleTV2,1

device model

deviceid

58:55:CA:1A:E2:88

MAC address of the device

features

0x39f7

bitfield of supported features

pw

1

server is password protected

The pw field appears only if the AirPlay server is password protected. Otherwise it is not included in the TXT record.

The features bitfield allows the following features to be defined:

bit

name

description

0

Video

video supported

1

Photo

photo supported

2

VideoFairPlay

video protected with FairPlay DRM

3

VideoVolumeControl

volume control supported for videos

4

VideoHTTPLiveStreams

http live streaming supported

5

Slideshow

slideshow supported

7

Screen

mirroring supported

8

ScreenRotate

screen rotation supported

9

Audio

audio supported

11

AudioRedundant

audio packet redundancy supported

12

FPSAPv2pt5_AES_GCM

FairPlay secure auth supported

13

PhotoCaching

photo preloading supported

 

这里需要说明的是,在Screen Mirroring(镜像)的功能处理中,airplay提供的端口号64885并未使用,而是client直接连接7100这个端口,关于这点在《Unofficial AirPlay Protocol Specification》中有相关描述。

Screen mirroring does not use the standard AirPlay service. Instead it connects to an apparently hard-coded port 7100

Airplay中的roap服务0C54A5569D80@iTools[CMCC-BAIJIE]._raop._tcp.local,这里的0C54A5569D80@iTools[CMCC-BAIJIE]做为name使用,且必须以这样的格式命名,不然airplay的手机端不会识别,0C54A5569D80串字符为本机的物理地址。

当pc上的接收端程序DEMOAirplayer应用退出时,也就是所注册的服务关闭时,mDNS广播服务注销消息,在数据包Answers中的服务项指定Time to live = 0,宣告服务停止。

 

 

 关于airplay协议实现镜像功能研究_第9张图片

 

=======================================

 

现在开始尝试注册自己的服务,希望最终能够达到可以镜像同步的目地。首先需要先注册一个自己的_airplay服务并发布到mDNS,这是第一步,也就是先要在IOS手机的airplay选项中找到自己,如果自己重新实现mDNS服务耗时就太长了,先做DEMO的话我们可以利用一下SDK中的例子,简单修改一下就OK,我在dns-sd 示例工程的main函数中加入下面代码:

 

#ifdef _DEMO
Demo:
	{

#define kRaopPort	50001
#define kAirplayPort	50002

		static DNSServiceRef airplayRef    = NULL;
		static DNSServiceRef raopRef    = NULL;

		Opaque16 AirplayPort = { { kAirplayPort >> 8, kAirplayPort & 0xFF } };
		Opaque16 RaopPort = { { kRaopPort >> 8, kRaopPort & 0xFF } };

		static const char AirplayTXT[] = 
			"\x1A" "deviceid=0c:54:a5:56:9d:80" \
			"\x0F" "features=0x3FFF"; \
			//"\x10" "model=AppleTV3,1";
			//"\x0E" "srcvers=150.33";

		static const char RaopTXT[] = 
			"\x06" "tp=UDP" \
			"\x08" "sm=false" \
			"\x08" "sv=false" \
			"\x04" "ek=1" \
			"\x06" "et=0,1" \
			"\x06" "cn=0,1" \
			"\x04" "ch=2" \
			"\x05" "ss=16" \
			"\x08" "sr=44100" \
			"\x08" "pw=false" \
			"\x04" "vn=3" \
			"\x09" "txtvers=1";
			

		err = DNSServiceRegister(&airplayRef, 0, opinterface, "JieTools", "_airplay._tcp.", "", NULL, AirplayPort.NotAnInteger, 0, NULL, reg_reply, NULL);
		if (!err) err = DNSServiceUpdateRecord(airplayRef, NULL, 0, sizeof(AirplayTXT)-1, AirplayTXT, 0);

		err = DNSServiceRegister(&raopRef, 0, opinterface, "0C54A5569D80@JieTools", "_raop._tcp.", "", NULL, RaopPort.NotAnInteger, 0, NULL, reg_reply, NULL);
		if (!err) err = DNSServiceUpdateRecord(raopRef, NULL, 0, sizeof(RaopTXT)-1, RaopTXT, 0);

		while(1)getchar();
		
		return 0;
	}
#endif

前两行定义指定服务端口,而后的AirplayTXT与RaopTXT分别两个服务的描述内容,下面对AirplayTXT做简单说明:

"\x1A"这样的写法,是为字符串前添加长度字值,为16进制,deviceid后面的值是本机网卡的物理地址,features这个参数不能少,它是airplay服务所支持的特性或能力描述,其它的参数可以忽略。

RaopTXT描述内容是我通过抓包COPY下来的,没有修改过;再接下来调用了两个mDNS SDK中的两个API,DNSServiceRegister用于注册,DNSServiceUpdateRecord用来更新服务的TXTRecord信息。

这里有两组调用服务注册,这里需要注意的是,如果你想实现_airplay服务,那么就必须将这两个服务一起注册,并且服务名称必须一致,如第四个参数是服务名称“JieTools”及“0C54A5569D80@JieTools”,注意命名规则。

 

OK,不出意外的话,运行它,打开你的手机,就能在airplay中发现自己注册的这个服务了。



未完待续 .....


 

 

 

你可能感兴趣的