news 2026/10/28 12:39:13

AirPlay投屏协议解析:Bonjour发现、TXT记录与反向连接

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AirPlay投屏协议解析:Bonjour发现、TXT记录与反向连接

简介:《Airplay 协议》是一份面向 iOS 与 Apple TV 互操作开发、协议逆向分析及智能硬件调试人员的英文协议说明文档,系统梳理苹果 AirPlay 协议族的实现机制与扩展细节。文档以非官方规范形式,围绕服务发现、照片与视频传输、音频流媒体、屏幕镜像、密码保护等模块展开,涉及 AirTunes 与 AirPlay 服务发布、RAOP、HTTP/RTSP 请求、RTP 流、音量与元数据控制、AirPort Express 认证、远程控制及时间同步等知识点,并附有历史沿革与 IETF RFC、草案、苹果协议等参考资源,便于读者建立从设备发现到媒体传输的完整协议视图。资源包共 1 个 doc 文件,约 511KB,内容按章节组织,适合作为协议查阅与实现对照的手册。目前已有 1432 人学习,可供从事投屏、多屏互动和苹果生态适配的开发者参考。

1. 手机点一下,电视就亮了:AirPlay 到底在忙什么

手机里存着一段视频,你在播放界面点了一下那个“屏幕套屏幕”的小图标,客厅的电视就亮起来开始放了。大多数人的第一反应是“蓝牙把文件传过去了”,或者“屏幕被实时录下来传过去了”——这两个猜测都不对,或者说只对了一小半。AirPlay 是一族协议的总称,它把整件事拆成四步:找到附近谁有能力接、和对方谈好用什么格式、把内容推过去、再把播放状态收回来。四步分别交给不同的协议完成,有现成的标准协议,也有自己加的扩展字段。搞懂这套分工,你才会明白为什么有时候投屏一秒就连上,有时候转半天圈连设备名字都刷不出来。

2. 设备是怎么互相认出来的:服务发现与一条自报家门的 TXT 记录

投屏列表弹出来的那三秒钟,屏幕上发生的事比想象中多。手机并没有一个“已知设备通讯录”挨个去拨号,它做的是在局域网里公开问一句“谁会放视频”,会放的那些设备自己举手应答。这套机制不需要账号、不需要提前配对、不需要在设置里填 IP,插上电、连上同一个网络就能被看见。整套发现流程建立在多播 DNS 之上,日常更常见的叫法是 Bonjour。

2.1 没有配对按钮,靠的是在局域网里“喊话”

多播 DNS 的思路很朴素:局域网里有一个约定好的多播地址和端口,任何设备都可以往那儿发问题,也可以监听那儿的问题。查询的域名以.local结尾,意思是“这个答案不需要去问外面的 DNS 服务器,本地就有人知道”。想找能放视频的设备,就查_airplay._tcp.local这类服务类型;想找能放音频的设备,就查_raop._tcp.local。

打个比方,这像是在一个没有物业的小区里找开锁师傅:不是挨家挨户敲门,而是站在院子里喊一嗓子“谁家会开锁”,会的人自己从窗户探头报名。喊话的人不需要知道院子里住了几户,也不需要维护一份名单,新搬来的人只要听得见就能应答。

这个设计带来两个直接后果。好处是零配置,设备换 IP、换网段、改名,都不影响发现;代价是它只在一个广播域内有效,跨路由器的两个网段之间默认互相听不见。很多“投屏搜不到设备”的现场,问题就出在这里:手机连的是 5G 频段的访客网络,电视插的是另一台路由器的 LAN 口,两边物理上在同一个屋子里,逻辑上是两个小区。

2.2 同一个设备上住着两套服务:RAOP 管声音,AirPlay 管画面

一个能接 AirPlay 的电视盒子,会同时广播两条服务记录。第一条叫 RAOP,全称是 Remote Audio Output Protocol,端口示例是 49152,专门负责音频流;第二条就叫 AirPlay 服务,端口示例是 7000,负责照片和视频内容。两条记录的服务名通常由设备的 MAC 地址加一个展示名拼成,形如“一串十六进制地址@客厅电视”,前半段保证唯一,后半段是给人看的。

为什么要分成两条而不是合并成一条?有历史原因——最早只有音频这一条路,后来才加上画面,为了不破坏已有的客户端,新能力就挂在新的服务类型下。也有现实好处:一个只带喇叭的音频设备可以只广播 RAOP,一个只做投屏的接收器可以只广播 AirPlay,双方都不必实现自己用不到的那部分。客户端查哪一条,就等于声明了“我要干什么”。

提示:看到_raop._tcp不要以为那是另一个厂家的协议,它就是 AirPlay 家族里负责音频的那一支,服务名一直没改。

2.3 TXT 记录:贴在门口的一张能力清单

发现到设备只是知道了“有这么个东西、IP 是多少、端口是多少”,还不足以决定要不要连。真正让客户端下判断的,是随服务记录一起发出来的 TXT 记录——一串键值对,相当于贴在门口的营业说明。RAOP 那条记录里的常见字段如下:

字段示例值含义
txtvers1这条 TXT 记录的格式版本
ch2声道数,2 表示立体声
cn0,1,2,3支持的音频编码编号列表
et0,3,5支持的加密类型编号列表
md0,1,2支持的元数据类型编号列表
pwfalse这台设备是否需要密码
sr44100采样率,单位赫兹
ss16采样位深,单位比特
tpUDP传输层用 TCP 还是 UDP
vs130.14服务端软件版本
am型号标识设备型号
sf0x4状态标志位

cn、et、md这三个字段的值都是编号,编号对应的含义是固定的:

编码编号 cn含义加密编号 et含义元数据编号 md含义
0PCM 未压缩0不加密0文本(曲名、艺术家)
1ALAC 无损1RSA(用于音频基站)1封面图
2AAC 有损3FairPlay2播放进度
3AAC-ELD 低延迟4MFiSAP(第三方设备)
5FairPlay SAPv2.5

这套自描述的价值在于解耦。客户端不需要内置一张“某年某型号支持什么”的对照表,它只要读一遍对方自报的能力,就能决定用 ALAC 还是 AAC 发、要不要带封面图、要不要弹密码框。厂家出新设备、加新编码,只要在 TXT 里多写一个编号,老客户端不认识这个编号,会自动跳过,不会崩。

2.4 位域 features:一个十六进制数里塞了十几项能力

AirPlay 那条服务记录用的是另一套描述方式,字段少但信息密度更高,其中最关键的是features,一个十六进制数,每一位代表一项能力。以0x39f7为例,把它展开成二进制,从最低位往高位读:

位号能力位号能力
0视频8屏幕旋转
1照片9音频
2视频 FairPlay 保护11音频包冗余
3视频音量控制12安全认证(SAPv2.5 + AES-GCM)
4HTTP Live Streaming13照片预缓存
5幻灯片
7屏幕镜像

光看表容易糊涂,写几行代码把它解出来最直观:

# 位号 -> 能力名称,只列文档里定义过的那几位 FEATURES = { 0: "视频", 1: "照片", 2: "视频FairPlay", 3: "视频音量控制", 4: "HTTP Live Streaming", 5: "幻灯片", 7: "屏幕镜像", 8: "屏幕旋转", 9: "音频", 11: "音频包冗余", 12: "安全认证", 13: "照片预缓存", } def decode_features(bitfield: int) -> list: # 右移 bit 位再和 1 相与,就是在问"第 bit 位是不是 1" return [name for bit, name in FEATURES.items() if (bitfield >> bit) & 1] print(decode_features(0x39f7))

这段代码没什么技巧,核心只有一行:(bitfield >> bit) & 1。把一个数右移若干位,最低位就变成了原来那一位的值,再和 1 做与运算,得到 0 或 1。用它扫一遍所有已定义的位号,就得到这台设备自报的能力清单。

0x39f7解出来的结果是:视频、照片、HTTP Live Streaming、幻灯片、屏幕镜像、屏幕旋转、音频包冗余、安全认证、照片预缓存。注意第 3 位(视频音量控制)和第 9 位(音频)是 0。前者说明这台盒子不支持在播放视频时调节音量——这个能力后来才被加进来,早期实现里干脆留空;后者说明音频不走这条服务,而是走 RAOP 那条,跟前面说的两套服务分工正好对上。

注意:位域是“自报”,不是“承诺”。广播里写了支持某一项,客户端连上去之后仍可能发现行为不完全一致;广播里没写,也不代表设备物理上做不到,只代表这条服务不负责。把位域当成线索,不要当成合同。

3. 三种内容三条路:照片、视频、音频各走各的通道

发现阶段结束,双方握手建立会话,接下来就该搬内容了。有意思的是,AirPlay 并没有给所有内容设计同一条管道。一张照片、一段视频、一路音频、一屏实时画面,走的是四种差别很大的传输方式,因为它们对延迟、对同步、对能不能中途改主意的要求完全不同。

3.1 照片:一次 PUT 就是一张图

最简单的是照片。客户端把 JPEG 的二进制数据直接塞进一个 HTTP PUT 请求的正文里,发给接收端的/photo路径,服务端回一个 200,图就显示出来了。整个交互干净得像往服务器上传一个文件:

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 二进制数据>

三个自定义头各管一件事。X-Apple-AssetKey是这张图的唯一标识,一串 UUID,后面做缓存要靠它认人;X-Apple-Transition指定用哪种转场效果把这张图推上来,示例里是溶解,不写就是硬切;Content-Length告诉服务端正文有多长,接收端据此知道读到哪儿算完。服务端返回 200 且正文为空,就表示图已经收下并显示。

转场名字不是随便编的,客户端可以先发一个GET /slideshow-features,把这个接收端支持的所有转场主题列出来。请求里带一个Accept-Language头,服务端就会用对应语言返回转场名称,返回体是一段 XML 属性列表,里面是一个themes数组,每项有key和name。这一步的意义在于让用户先挑效果,再开始放,而不是放起来之后才发现这台设备不支持某种花哨的切换。

3.2 幻灯片与预缓存:为什么要提前塞几张图进去

单张照片是一次请求,幻灯片就是一串请求加一份配置。客户端先GET /slideshow-features拿主题,再用PUT /slideshows/1把设置推过去,正文是一段 XML 属性列表,里面写三样东西:settings.slideDuration是每张停留的秒数,settings.theme是选中的转场主题,state是playing或stopped。服务端回一个空的字典表示收到,之后客户端就按节奏一张张 PUT 图片。要停的时候,发一个POST /stop。

真正有意思的是缓存机制。切图如果每次都从头传一张几兆的 JPEG,转场动画必然卡在半路等数据。协议里给出的解法是让客户端提前把相邻的几张图“预存”进去:在 PUT 请求里带上X-Apple-AssetAction: cacheOnly,服务端收到后只把图存进缓存,不显示。等真正要切到那张图时,客户端再发一次请求,动作换成displayCached,带上同一个X-Apple-AssetKey,服务端直接从缓存里取,不用再传一遍数据。

这个设计思路在工程上很常见:把“传输”和“呈现”拆成两个时刻。传输可以慢慢来、可以提前做,呈现必须准时。这也是为什么翻幻灯片时,第一张总有点迟疑,后面几张反而顺——缓存被填热了。

3.3 视频:请求加上事件回报

视频这一路走的是 HTTP 请求,客户端告诉接收端要放什么,接收端自己去取、自己缓冲、自己解码。这一点很关键:视频数据并不是由手机一路实时推过去的,手机更像一个遥控器加一份播放清单。好处是手机可以锁屏、可以切到别的应用,播放不中断;坏处是接收端必须能独立访问到那个媒体地址,如果视频存在手机本地、接收端又拿不到,就得换一条路。

伴随视频的还有事件。播放开始、暂停、播完、出错,这些状态变化需要回传给客户端,让手机上的进度条跟电视上的画面对得上。事件不是客户端轮询问出来的,而是接收端主动推过来的,推的通道就是后面第 4 章要讲的反向连接。

3.4 音频:先用 RTSP 谈条件,再用 RTP 送数据

音频是四路里最讲究的一路,因为它对时间最敏感。它用的控制协议是 RTSP,一个专门为流媒体设计的协议,长得像 HTTP,但语义是“会话式”的:先描述要放什么,再建立传输通道,然后播放、暂停、调整、结束。和 HTTP 的一次请求一次响应不同,RTSP 允许一个会话持续存在,双方在会话期间一直保持状态。

条件谈好之后,真正的音频数据走 RTP。RTP 的每个包里都带序号和时间戳,接收端靠序号发现丢包、靠时间戳把采样排回正确的位置。这也是为什么 TXT 记录里要自报sr(采样率)和ss(位深)——发送端必须先知道对方的时钟基准,才能把时间戳算对。传输层可以是 UDP 也可以是 TCP,前者快但可能丢,后者稳但延迟高,具体用哪个由tp字段和实际协商决定。

音频这条线上还挂着几样附属能力。音量控制让客户端能远程调接收端的输出电平,而不是去调自己的媒体音量;元数据(md字段里声明的文本、封面、进度)让接收端的屏幕上能显示曲名和专辑图,哪怕手机已经锁屏;远程控制让接收端的按键或遥控器能把“下一首”“暂停”这类指令送回手机。此外还有认证环节,用于音频基站这类设备,走的是 RSA 那一套。

注意:原始文档明确说明它不提供任何 RSA 密钥,也不解释受 DRM 保护的内容如何解码。也就是说,协议层描述的是“怎么把已解码的数据送过去”,不是“怎么把加密内容解开”。这两件事经常被混为一谈。

3.5 屏幕镜像:一边编码一边对表

屏幕镜像和前面三种都不一样。照片、视频、音频都是有明确终点的内容,镜像没有——它是一路持续的、实时的画面。手机必须把当前屏幕一帧帧编码成视频流推过去,接收端边收边解码边显示。

这件事对硬件有硬性要求:编码必须由专门的硬件完成,不能靠通用处理器软编,否则 CPU 会被吃满、手机发烫、帧率掉到个位数。文档里明确写了,屏幕镜像只在具备这种硬件编码能力的设备上可用,老设备直接被排除在外。这也解释了一个常见困惑:同一款应用,在新手机上能镜像,在老手机上那个按钮是灰的——不是软件不想支持,是硬件扛不住。

镜像这条路上还有一个容易被忽略的环节:时间同步。实时画面和声音要一起出来,接收端收到的一堆流包必须按统一的时间基准排好队再播放,早到的等一等,晚到的丢掉或者补帧。这一步借用了网络时间协议那套思路,让两端对同一时刻的理解尽量一致。没有它,画面和声音就会逐渐漂移,播几分钟之后口型对不上。

4. 为什么要有“反向连接”:一条被倒过来用的 HTTP

前面反复提到“事件回传”,但用普通 HTTP 很难做到这件事。HTTP 是请求-响应模型:客户端开口,服务端回答。服务端手里没有客户端的“电话号码”,它没法主动敲客户端的门说“我播完了”。这是一条硬约束,AirPlay 为了绕开它,做了一件挺聪明的事。

4.1 普通 HTTP 的死角:服务器没法主动说话

假设只有普通 HTTP,客户端想知道播放状态,有两条路。一条是轮询:每隔一秒发一次请求问“现在什么状态”,绝大部分回答都是“没变”,白白浪费请求和电量,而且从状态变化到被发现之间总有一个间隔。另一条是长轮询:发一个请求挂在那儿不返回,等服务端有话说再返回,然后立刻再发一个。这条路能用,但实现别扭,中间任何一个代理或超时都可能把连接掐断。

对一个要在客厅里连续放两小时电影的场景来说,这两种方案都不体面。协议的设计者选了第三条路:干脆开一条连接,方向反过来用。

4.2 PTTH:把方法名倒过来写

客户端在正常的 HTTP 会话之外,再向接收端的 7000 端口发起一条连接,请求长这样:

POST /reverse HTTP/1.1 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

服务端如果同意,回一个101 Switching Protocols,连接就从普通 HTTP 升级成一条双向通道。注意Upgrade头里的PTTH——就是HTTP反过来拼的,一个藏在协议里的玩笑。升级之后,这条连接上不再是“客户端问、服务端答”,而是服务端随时可以发一个POST /event过来,客户端回一个 200 表示收到。

X-Apple-Purpose: event这个头是给接收端看的说明书:这条连接专门用来发事件,不要拿它干别的。X-Apple-Session-ID则是把这条反向连接和主连接绑定在一起的钥匙——一个客户端可能同时开着好几条会话,接收端必须知道这个事件该算到哪一次播放头上。

4.3 会话 ID:把两条连接缝成一条

正向连接和反向连接是两个独立的 TCP 连接,操作系统层面毫无关系。把它们变成“同一次会话”的,就是那个X-Apple-Session-ID,一个 UUID,在两条连接的所有请求里都带上。除此之外,每个 HTTP 请求还会带X-Apple-Device-ID,值是设备的 MAC 地址,用来标识“是谁在说话”。

这种设计的好处是解耦。接收端不需要维护一张“哪个 IP 对应哪个客户端”的表,它只认会话 ID;客户端也不需要保证两条连接从同一个源端口出去,只要 ID 一致就行。代价是 ID 变成了唯一的身份凭据,一旦泄漏,别人就能冒充你的会话收发事件。

4.4 事件报文长什么样

事件本身的格式是 XML 属性列表,和前面幻灯片设置用的是同一套。以照片会话结束为例,接收端发过来的是这样一段:

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"?> <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>

三个键读起来很清楚:category说明这是哪一类事件,sessionID是会话编号,state是状态值。照片会话只有stopped一个状态,意思是“结束了,你可以安全断开”。幻灯片的状态多一些,有loading、playing、stopped三种,还会额外带一个lastAssetID,告诉客户端“我最后显示到第几张”,客户端据此知道下次该从哪儿接着放。

提示:事件的方向要记清楚。照片和幻灯片的事件是接收端发给客户端的(通知状态变化),而幻灯片播放状态的事件也可以是客户端发给接收端的(告知自己这边的情况)。同一个/event路径,两个方向都用,靠会话 ID 区分。

5. 几个最容易搞混的地方:AirPlay 不等于投屏,也不等于蓝牙

概念解释到这儿,剩下的风险不是“不懂”,而是“懂了一半”。下面这几组词,日常对话里经常被当成同义词互换使用,但在协议层面它们指的东西差别很大,混着用会在排查问题时把你带偏。

5.1 AirPlay 和 AirTunes:改的是名字,留的是服务名

AirTunes 是这套协议最早的名字,那时候它只干一件事:把音频从电脑送到带音箱的网络基站。后来视频能力被加进来,名字改成了 AirPlay,但底下的服务发现记录一直没改名,还是_raop._tcp。所以在网络扫描结果里看到 RAOP,不要以为那是某个不相干的第三方协议——它就是 AirPlay 的音频分支,只是名字停留在了过去。

这个区别在排查时很有用。如果你在列表里能看到设备但放不出声音,先看 RAOP 那条服务有没有广播、TXT 里的cn里有没有你打算用的编码;如果你能看到设备但投不了画面,该看的是 AirPlay 那条服务里的features位域。

5.2 镜像和投放:一个是录屏直播,一个是把地址递过去

“投屏”这个词在日常里覆盖了两件事,协议层把它们分得很开。屏幕镜像(Screen Mirroring)是把整个屏幕实时编码成视频流推过去,接收端看到的是你手机上的一切,包括通知、误触、横竖屏切换。媒体投放是把内容的地址或数据交给接收端,让它自己取、自己播,手机只是个遥控器。

两者的成本差得很远。镜像必须持续编码,手机一定发热、一定耗电,画质受编码码率和网络抖动影响;投放的负担在接收端,手机可以锁屏走人。所以判断该用哪种,看的是“我要不要连操作界面一起给对方看”。只想看个片子,用投放;要演示 App 怎么点,才用镜像。照片的 PUT 上传其实属于第三类——既不是镜像也不是投放,而是“把数据推过去让对方显示”。

5.3 和蓝牙、DLNA 比,差在哪

维度AirPlay蓝牙音频DLNA
传输介质局域网(Wi-Fi 有线皆可)短距无线,点对点局域网
发现方式多播 DNS 自动发现配对UPnP 广播发现
数据流向推流,接收端可回传事件推流,几乎无回传通常是把地址给接收端,让它自己拉
时间同步有专门的对时环节依赖编解码器缓冲较弱,多设备同步困难
典型短板只在一个广播域内有效带宽有限,压缩重格式兼容性靠协商,体验参差

把这张表浓缩成一句话:蓝牙解决的是“一对一、离得近”,DLNA 解决的是“把地址给你、你自己想办法播”,AirPlay 解决的是“我知道你有什么能力、我按你的能力推、你还要把状态告诉我”。第三件事里的“回传”是它和另外两者最本质的分野。

5.4 密码保护和内容加密:门锁和保险柜

这两个词经常被合并成“加密”,其实是两层完全不同的东西。密码保护是准入控制,反映在服务发现里就是那个pw字段——只有接收端设置了密码,这个字段才会出现在 TXT 记录里,客户端看到它才会弹密码框。它管的是“你能不能进来”。

内容加密是另一回事,对应 TXT 里的et字段:0 表示不加密,1 是 RSA(音频基站那类设备用),3 和 5 是不同版本的 FairPlay 方案,4 是面向第三方设备的方案。它管的是“进来的数据能不能解”。原始文档在这里划了一条很清楚的线:它不提供任何 RSA 密钥,不解释受 FairPlay 保护的内容怎么解码,也不解释手机端用来保护音频和屏幕内容的那套认证。也就是说,协议文档描述的是管道形状,不是钥匙。

注意:很多人看到“支持 AirPlay”就以为能放任何内容,实际卡住的地方往往就在这一层。能不能连上、能不能解码,是两个独立的问题。

5.5 “支持 AirPlay”这句话的三种含金量

同一个说法,可能指三件不同的事。第一种是“能被发现”:设备在网络上广播了_airplay._tcp服务,客户端列表里能看到它的名字。第二种是“能用某项功能”:features位域里对应位是 1,客户端据此启用对应按钮。第三种是“通过认证”:这是商业层面的合规声明,和协议能不能跑通没有必然关系。

三种含义混在一起,就会出现“列表里有它、点了没反应”的现场。这时候该做的不是反复重启,而是去看那段 TXT 记录:位域里到底声明了什么,pw在不在,model和vs是什么。这些字段是排查的起点,比猜有用得多。

6. 什么时候该用它,什么时候绕开走

理解了这套分工,判断就变得很直接。适合的场景几乎都集中在一个前提下:设备和接收端在同一个局域网、同一个广播域内,且你需要的不只是“把画面弄过去”,还包括状态回传和多设备协同。不适合的场景,也几乎都能归结为这个前提被打破,或者你要解决的问题根本不在协议覆盖范围内。

场景建议原因
家里把手机视频放到客厅大屏用同一网段,发现和投放都很顺
会议室轮流演示,需要展示操作过程用镜像要连界面一起给对方看
只放一段本地音频到音箱用 RAOP 那一路负担小,元数据能显示在音箱屏上
手机连访客 Wi-Fi,电视在另一网段换网络或加中继多播发现跨不了广播域
需要把画面同步到十几个房间另找方案协议本身不解决大规模同步分发
只想在局域网里传一个文件别用一个 HTTP 请求就能解决,不必上这套会话机制
播放受保护的内容先确认解码链路协议层不提供密钥,也不解释 DRM 解码

拿一个具体例子走一遍。你在会议室,笔记本和投影盒子都连着同一个内网,要把一段演示视频投上去。先看服务发现:盒子的_airplay._tcp能不能被扫到、features里视频位是不是 1。能扫到、位是 1,就发 HTTP 请求把媒体地址递过去,同时开一条/reverse连接等着收事件。播放中如果发现进度条不动,先看反向连接有没有成功升级到 101,再看/event有没有正常 POST 过来——卡在这一步的话,问题在事件通道,不在视频本身。

很多时候我会用一个最土的办法验证:先不看界面,直接把那条服务记录打印出来。

# 在局域网内列出广播了 _airplay._tcp 的设备及其 TXT 记录 # 命令名各系统不同,能把 SRV 和 TXT 一起打出来即可 avahi-browse -rt _airplay._tcp

输出里该关注四样东西:端口是不是你以为的那个、model和vs是不是和实物对得上、features解出来缺了哪几位、pw在不在。这四样一对,八成的“为什么连不上”现场就有方向了,剩下的才是抓包看请求。

我踩过的坑是反过来:一开始总盯着应用层的报错,反复重装、反复重启设备,折腾半天;后来才养成习惯,任何一次投屏出问题,先去把那段 TXT 记录完整读一遍,确认对方的自报能力和我的预期一致,再往下查。这个顺序换过来之后,很多玄学问题当场就变成了明确的一行字段差异。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/28 12:38:53

AI前端代码如何做到无可挑剔:CLI与浏览器扩展实战

1. 从"impeccable"这个词说起&#xff1a;一个前端工程师的执念第一次看到"impeccable"这个词&#xff0c;是在一个前端设计工具的讨论帖里。这个词翻译过来是"无可挑剔的、完美的"&#xff0c;放在前端开发语境下&#xff0c;它指向的其实是一个…

作者头像 李华
网站建设 2026/10/28 12:38:40

impeccable规范:项目元契约驱动的CLI工程化实践

1. 项目概述&#xff1a;一个被严重误读的“完美主义”CLI工具最近在多个前端协作群和开源社区里&#xff0c;频繁看到有人发问&#xff1a;“impeccable 怎么用&#xff1f;”、“npx impeccable 安装失败”、“claude mcpservers npx 是什么鬼&#xff1f;”&#xff0c;甚至…

作者头像 李华
网站建设 2026/10/28 12:38:39

远程桌面连接入门指南:从零开始实现远程控制电脑

简介&#xff1a;这份资源是一份面向IT运维人员、技术支持及普通办公用户的远程桌面操作说明文档&#xff0c;围绕Windows XP系统自带的远程桌面功能展开&#xff0c;帮助读者理解如何通过客户端与服务器端配置实现跨地域的电脑控制&#xff0c;解决远程办公、系统维护与用户管…

作者头像 李华
网站建设 2026/10/28 12:38:03

JSP+Servlet构建中小学教师工作管理系统实战

1. 项目概述与核心需求JSP中小学教师工作管理系统是一套面向基础教育领域的综合性管理平台&#xff0c;旨在解决传统纸质化办公效率低下、数据统计困难等问题。系统采用B/S架构&#xff0c;基于JSPServlet技术栈实现&#xff0c;包含教师档案管理、课程安排、考勤统计、绩效评估…

作者头像 李华
网站建设 2026/10/28 12:37:00

智能体技能库设计:从Prompt膨胀到按需加载的技能编排

前阵子我们团队在给一个内部智能体平台做能力升级&#xff0c;遇到一个特别让人头大的问题&#xff1a;业务方接二连三提出新场景&#xff0c;每个场景我们都要往 system prompt 里塞一大段指令&#xff0c;再挂上一堆工具函数。结果不到两个月&#xff0c;主 prompt 就膨胀到四…

作者头像 李华
网站建设 2026/10/28 12:36:55

Base64编码解码工具:原理、实现与常见问题排查

上周帮一位开发者排查接口问题&#xff0c;他甩过来一串eyJ1c2VySWQiOjEwMjR9&#xff0c;问我是不是被加密过的密码。我当场解给他看&#xff0c;就是一段明明白白的 JSON。这个误会我遇到过太多次了&#xff0c;Base64编码解码工具看起来简单到不值一提&#xff0c;但它恰恰是…

作者头像 李华