源码根:foundation/CastEngine/castengine_cast_framework/,以下函数与行号均已在本机 6.1 LTS 源码逐一核实。
0. 先建立整体心智模型
一次 Cast+ 投屏 = 两条通道 + 六个阶段:
| 通道 | 建立方 | 软总线 API | 用途 |
|---|---|---|---|
控制/协商通道 CastPlusSessionName | Sink(SessionServer::CreateListenSocket) | Socket/Bind/Listen | 设备咨询、会话协商数据 |
数据握手通道 com.huawei.android.airsharing+CastPlusDiscoveryModule | Sink(SinkSessionRcvServer) | Session 会话 | 握手 JSON → DM 认证 |
六个阶段:① Sink 服务启动 → ② 发现(Sink 发布)→ ③ Source 连接+协商 → ④ Sink 握手认证(DM)→ ⑤ 会话建立+RTSP M1-M4 → ⑥ 媒体播放(Mirror/Stream)。
关键分工:认证完全交给 DM(CastEngine 只注册回调消费结果),组网由 DM 内部完成,CastEngine 自己只管两条业务通道。
阶段一:Sink 服务启动
入口 REGISTER_SYSTEM_ABILITY_BY_ID(CastSessionManagerService, CAST_ENGINE_SA_ID, false)(cast_session_manager_service.cpp:69),进程启动后走 OnStart()(:256):
OnStart()
├─ Publish() // 发布 SA
├─ SinkSessionRcvServer::CreateSinkSessionListener() // :270 数据握手通道
│ └─ CreateSessionServer(pkgName=devicemanager,
│ "com.huawei.android.airsharing+CastPlusDiscoveryModule") // 软总线会话
├─ SessionServer::CreateListenSocket() // :278 控制通道,50ms×1200 次重试
│ └─ Socket("CastPlusSessionName") → Listen(socketId, qos, 3, &listener)
├─ RegisterCollaborationListen()
└─ RegisterSinkAuthCallback() // :320
└─ DeviceManager::RegisterSinkBindCallback(PKG_NAME, CastSinkAuthCallback)
控制通道 listener 的 4 个回调(:135-179)是后续所有协商逻辑的入口:
OnBind→OnConsultSessionOpened(Source 连上来了)OnBytes→ConnectionManager::OnConsultDataReceived(Source 发来协商数据)OnNegotiate2→ConnectionManager::OnNegotiate2(ACL 鉴权钩子,软总线在建连时回调)OnShutdown→CancelStartProjectionClientAbility
排查要点:日志出现 Create session server SUCCESSFULLY. 说明控制通道监听成功,否则 Source 永远连不上。
阶段二:Sink 打开"可发现"开关
用户在大屏打开投屏开关 → SetDiscoverable(true)(:943):
SetDiscoverable(enable)
├─ WifiDisplayManager::StartListen()
├─ ConnectionManager::EnableDiscoverable()
└─ DiscoveryManager::StartAdvertise(15, 3) // capability=15(MIRROR|STREAM|COOPERATION|HICAR), medium=3(BLE|COAP)
└─ DeviceManager::StartAdvertising(advertiseParam, callback)
└─ (DM 内部) PublishSoftbusLNN() // 软总线发布 LNN
StartAdvertise(discovery_manager.cpp:232)组装 customData:castPlus="CA60",其中 bit1=AUTH_VERSION、bit6=HMOS 标识、bit7=华为标识。Source 侧解析这段数据判断对端能力(discovery_manager.cpp:442 有对称的解析逻辑)。
阶段三:Source 发起连接与协商(重点分支多)
Source 手机点击大屏后,软总线 Socket 连到 CastPlusSessionName,触发 Sink 侧回调链:
Sink: OnNegotiate2 (cast_session_manager_service.cpp:176)
Source 侧对称逻辑 OnConsultDataReceivedFromSink(:505)→ handleConsultData(:543)按 Sink 回传结果分支:AUTH_SUCCESS_FROM_SINK→正常进入下一步;CONNECTION_FAILED→断连并打点 S8_CONSULT_DATA。
协商数据里的 IP/端口是加密的:QueryP2PIp(:987)先通过 DM BindTarget(ACTION_QUERY_P2P_IP) 查 P2P IP,GetConsultationData(:1045)用会话密钥调 EncryptIp/EncryptPort 加密后传输。
阶段四:Sink 数据通道握手认证(ConnectionManagerSink,分支最多的环节)
Source 在数据会话(AirSharing 会话)上发握手 JSON,Sink 侧入口 ConnectionManagerSink::OnSinkDataReceived(connection_manager_sink.cpp:65):
OnSinkDataReceived (:65)
ReplyAuthFailed(:243)内还有 PIN 重试分支:IncreasePinRetryCnt()(:281)超阈值则直接失败。DM 内部的具体认证状态机(PIN 弹窗、v2 凭据认证)在 DM 模块,可配合 openharmony-dm-auth skill 看。
阶段五:会话建立——状态机 + 连接四步
5.1 状态机(include/cast_session_common.h:32 + cast_session_state.cpp)
状态:DEFAULT → DISCONNECTED → CONNECTING → CONNECTED → PLAYING,旁路 PAUSED / AUTHING / DISCONNECTING / MIRROR_TO_STREAM / STREAM_TO_MIRROR 等。
实现是经典的 State 模式(每个状态一个类,Enter() + HandleMessage(msg)),消息驱动迁移(cast_session_state.cpp):
DefaultState --收设备 ready--> DisconnectedState
DisconnectedState --MSG_START_AUTH--> AuthingState (启动 MSG_CONNECT_TIMEOUT 定时器)
--MSG_CONNECT-----> ConnectingState
AuthingState --MSG_CONNECT-----> ConnectingState (认证成功回调触发)
ConnectingState --MSG_SETUP------> 触发 ProcessSetUp
ConnectedState --MSG_PLAY-------> PlayingState
ConnectedState --MSG_PAUSE------> PausedState
任意状态 --MSG_DISCONNECT/ERROR/超时--> DisconnectingState → DisconnectedState
超时保护:进入 Authing/Connecting 都 SendCastMessageDelayed(MSG_CONNECT_TIMEOUT, TIMEOUT_CONNECT),迁移时 RemoveMessage 取消。
5.2 连接四步(cast_session_impl.cpp)
AddDevice (:307) → 状态机进 Authing → ProcessAuth (:1084) // 6.1 LTS 中实际由 DM 认证链路驱动
阶段六:RTSP M1-M4 能力协商
RTSP 报文入口 RtspController::OnRequest(rtsp_controller.cpp:194),用函数表 requestFuncMap_ 按方法名分发(:1527-1535):
| 消息 | 方法 | 处理函数 | 行号 | 作用 |
|---|---|---|---|---|
| M1 | OPTIONS | ProcessOptionRequest | :407 | 能力询问,回响应后发 SendOptionM1M2,waitRsp_=WAITING_RSP_OPT_M2 |
| M2 | ANNOUNCE | ProcessAnnounceRequest/DealAnnounceRequest | :349/:292 | Source 宣告属性(分辨率、音视频格式、UIBC 能力) |
| M3 | GET_PARAMETER | ProcessGetParameterRequestM3 | :447 | 取参数集 |
| M4 | SET_PARAMETER | ProcessSetParamRequestM4 | :651 | 设定会话参数、加密算法 |
| — | SETUP | ProcessSetupRequest | :431 | → listener_->OnSetup → ProcessSetUp |
| — | PLAY | ProcessPlayRequest | :501 | → listener_->OnPlay → ProcessPlay |
| — | PAUSE/TEARDOWN | ProcessPauseRequest/ProcessTearDownRequest | :534/:558 | 暂停/拆会话 |
| — | RENDER_READY | ProcessRenderReadyRequest | :585 | 对端渲染就绪 |
| — | 事件通道 | ProcessEventChangeRequest | :479 | Mirror↔Stream 切换、反控事件都走这里 → NotifyEventChange |
| — | Trigger | ProcessGetTrigger | :461 | 触发类事件 |
保活:OnTimeKeepAlive(:318)→ RtspChannelManager::ScheduleKeepAlive(:239),KeepAlive 间隔通过 SET_PARAMETER 协商。
阶段七:Mirror 镜像媒体链路(Source 推流 → Sink 解码上屏)
Source 端:VirtualDisplay(虚拟屏录屏采集)→ VideoEncoder(H264/H265 编码)→ RtpPackager(RTP 封包)→ send_queue → 软总线通道。
Sink 端接收解码链路(session/src/mirror/src/):
rtp_depackager.cpp DoRtpDepackagerParamCheck (:44) // 校验 RTP 版本、payloadType(AVC=视频/AAC=音频)
排查口诀:video first frame. 是"投屏上屏成功"的硬指标;earlyUs 为正偏大=音频落后(丢音频),为负偏大=视频落后(丢视频)。
阶段八:反控(UIBC)与 Mirror↔Stream 切换
反控(remote_control_sink.cpp):Sink 捕获遥控器/键鼠事件 → OnInputEvent(:138)→ ConstructRemoteCtrlPacket(坐标映射基于 UpdateVideoSize/UpdateWindowSize 更新的 video/屏幕尺寸)→ SendPacket 发给 Source → Source 侧 depacketizer 解析解密 → 注入全局输入。M2/M3 协商里的 genericList 能力决定是否支持。
Mirror↔Stream 自动切换(cast_session_impl.cpp):Source 检测到影音播放 → 发事件通道报文 → ProcessMirrorToStream(:1418)= PauseMirrorForStream + SendEventChange(MIRROR_TO_STREAM),Sink 转 CastStreamPlayer 拉流播放(Source 可熄屏);播放结束 → ProcessStreamToMirror(:1435)切回。日志特征:Transfer to MIRROR_TO_STREAM。
完整时序(正常投屏一次):
Sink 启动 → 两条通道监听 → SetDiscoverable(true) → PublishSoftbusLNN Source 发现 → DM 组网 + PIN 认证 → Socket 连 CastPlusSessionName Sink OnNegotiate2(ACL) → OnBind → OnConsultSessionOpened Source 发协商数据 → OnConsultDataReceived → Source 创建会话 数据通道握手 → DM BindTarget 认证 → AUTH_FINISH → 握手回复 RTSP: M1→M2→M3→M4 → SETUP(建通道) → PLAY(起播) Sink "video first frame." → 上屏 → 反控/切换事件 → TEARDOWN 结束
建议的源码阅读顺序
cast_session_manager_service.cpp:OnStart / SetDiscoverable / CreateCastSession / CastSinkAuthCallbackdevice_manager/src/discovery_manager.cpp:StartAdvertise 参数组装device_manager/src/connection_manager.cpp+connection_manager_sink.cpp:所有分支逻辑(状态分支最值得精读)session/src/cast_session_state.cpp:状态机骨架 →cast_session_impl.cpp四步session/src/rtsp/src/rtsp_controller.cpp:报文分发session/src/mirror/src/video/:解码与音画同步session/src/stream/:Stream 模式(CastStreamPlayer)

393

被折叠的 条评论
为什么被折叠?



