这篇写什么?
做 Soundbar + Dolby FlexConnect / 校准时,最容易混在一起的三件事是:
- modelName 怎么对应到 JSON?
- FlexConnect 初始化谁调?
- 音箱连没连怎么报给 Dolby?
下面用「六层分层图」把整条链路摊开:左右是谁定的、JSON 管不管左右、两套 API 各在哪一层。
一句话:
硬件 RF → 串口 → App Bridge 定角色/modelName → IDeviceConnection 报名单
→ Dolby 按型号加载 JSON → FlexCalibrator.setDevices 初始化 → 可校准 / UI 显示
「分层图」:从下到上共 6 层
| 层 | 内容 |
|---|---|
| ⑥ | 用户看到的校准结果 / UI |
| ⑤ | Dolby Calibration + FlexConnect(读 JSON、初始化、开校准) |
| ④ | IDeviceConnection(AIDL:App 上报 Device[]) |
| ③ | 校准 App Bridge(定角色、贴 modelName) |
| ② | 串口协议(AT+GET_RFSTATUS) |
| ① | 硬件 RF(左 / 右 / 低音炮真连接状态) |
左右是谁定的?在第 ①②③ 层就定完了。
第 ⑤ 层的 JSON 不负责判断左右,只负责「这种型号的音箱声学参数怎么配」。
整条链路详解
第 ① 层:硬件
Soundbar 主机上有 RF 模块。无线左环绕 / 右环绕 / 低音炮连上或断开,硬件是知道的。
第 ② 层:串口问硬件(Bridge 去查)
Bridge 绑 OemSerialPortRouter,周期发:
AT+GET_RFSTATUS
MCU / RF 回类似:
GET_RFSTATUS_SBAR51_101
███
││└─ Z = 低音炮(1=连, 0=断)
│└── Y = 右环绕
└─── X = 左环绕
例:101 → 左连、右断、低音炮连。
到这里,App 只知道「三个开关」:左 / 右 / 低音炮通不通。
还不知道 Dolby 的 modelName,也还没碰 JSON。
第 ③ 层:App Bridge 定身份
Bridge 用写死的规则(或读可选的 device_role_map.json):
| RF 结果 | OEM 内部 ID | 角色 | 贴给 Dolby 的 modelName |
|---|---|---|---|
| 主机 | soundbar_main |
主机 Controller | OEM_5ch_ISS |
| 左=1 | rear_left |
左环绕 | OEM_1ch_WS_L |
| 右=1 | rear_right |
右环绕 | OEM_1ch_WS_R |
| 低音炮=1 | subwoofer_main |
低音炮 | OEM_SUB |
对 RF=101,Bridge 组装出的名单是:
soundbar_main→ OEM /OEM_5ch_ISS(主机,必报)rear_left→ OEM /OEM_1ch_WS_L(左,连了才报)subwoofer_main→ OEM /OEM_SUB(低音炮,连了才报)- (右环绕不报,因为右=0)
每个设备填成 Dolby 规定的 Device 结构:
Device {
address.id = "rear_left" // 起的唯一名
isMovable = true // 卫星/低音炮可移动;主机 false
hardwareId.manufacturerName = "OEM"
hardwareId.modelName = "OEM_1ch_WS_L" // ★ 身份钥匙
}
左右是在这一步由「RF 位 + OEM 角色表」定死的。
App 不会打开 OEM_OEM_1ch_WS_L.json 来判断「这是不是左环绕」。
同一份 RF 状态还会更新 App 主页音箱列表、断连弹窗——那是 UI,和 Dolby 并行。
第 ④ 层:交给 Dolby(AIDL 上报)
Manifest 里挂 Dolby 约定的 Action:
com.dolby.android.audio.intent.action.AUDIO_DEVICE_CONNECTED
Dolby 的 DolbyAudioCalibrationService 启动后:
- 用这个 Intent 找到 App 的 Bridge
bindService- 调
addCallback(listener) - 之后有变化时立刻调:
listener.onDevicesChanged(devices)
这就是 IDeviceConnection 这一层:只做「报名单」,不做声学初始化。
第 ⑤ 层:Dolby 加载 JSON + 初始化 FlexConnect
Calibration 收到 Device[] 后,对每一个设备:
- 取出
manufacturerName+modelName
例:OEM+OEM_1ch_WS_L - 拼文件名:
OEM_OEM_1ch_WS_L.json - 到目录找:
/vendor/etc/dolby/audio/device_descriptors/ - 核对 JSON 里的
identifier是否等于modelName(必须一致) - 读描述符内容(声学 / 渲染参数),例如:
- 主机 JSON:
render_outputs有 5 路(对应主机 5 声道) - 左环绕 JSON:
render_outputs有 1 路 - 低音炮 JSON:
render_outputs有 1 路
- 主机 JSON:
- 内部走类似
setDevices/ device connector 初始化(AIDK 里FlexCalibrator那套)
第 ⑥ 层:和音频输出怎么对上
平台还有 8 声道 ALSA 布局(和角色表一致):
ch0~4 = 主机 FL/FR/FC/LS/RS
ch5 = 左环绕
ch6 = 右环绕
ch7 = 低音炮 LFE
device_role_map 里也写了:
- 左 → ALSA ch5
- 右 → ALSA ch6
- 低音炮 → ALSA ch7
含义是:FlexConnect / 校准认为「左环绕」时,声音应走到 ch5;
所以 App 必须把「物理左 RF」稳定映射成 OEM_1ch_WS_L,不能左右填反。
上报顺序也建议固定:主机 → 左 → 右 → 低音炮(与 init_order 一致),因为 Dolby 文档里设备列表顺序会影响 flexible rendering 声道编排。
完整例子串起来
假设某时刻:左环绕连上、右环绕没连、低音炮连上。
- ① 硬件:左 RF 通,右 RF 断,Sub RF 通
- ② 串口:
GET_RFSTATUS_SBAR51_101 - ③ App Bridge:认定 → 主机 + 左 + 低音炮;填
modelName→OEM_5ch_ISS,OEM_1ch_WS_L,OEM_SUB(此时仍未读 JSON) - ④
onDevicesChanged([主机, 左, 低音炮]) - ⑤ Dolby:打开
OEM_OEM_5ch_ISS.json、OEM_OEM_1ch_WS_L.json、OEM_OEM_SUB.json,各自做 device connector / FlexConnect 初始化 → 可以开始校准 - ⑥ UI:主页也显示主机 / 左 / 低音炮在线,右不显示
若下一步右环绕也连上(RF 变成 111):
- Bridge 重新上报 4 个设备
- Dolby 再多加载
OEM_OEM_1ch_WS_R.json,并重新初始化
两层 API 在整条链里的位置
①②③④ ←── IDeviceConnection(App 侧实现:报「连了谁、叫什么型号」)
│
▼
⑤ ←── device connector / FlexConnect 初始化
(Dolby Calibration 内部:按型号加载 JSON 并开工)
不是同一个 API:
- 前者 = 报名单
- 后者 = 按名单给每个设备做初始化
三个问题的直接回答
总览:谁负责哪一段?
| Dolby 要确认的事 | 实际接口 | 谁写 / 谁调 |
|---|---|---|
| ① modelName 怎么加载 JSON | DeviceEventHandler.loadDescriptor(manufacturer, modelName) |
Dolby Calibration 内部 |
| ② 初始化 FlexConnect | FlexCalibrator.setDevices(List<Device>) → native setDevice(...) |
Dolby Calibration 内部 |
| ③ 音箱连接状态 | IDeviceConnection + onDevicesChanged(Device[]) |
OEM Bridge 实现并上报;Dolby bind 后收回调 |
1. modelName → JSON(代码级)
不是 OEM 调的 API。 在 Dolby 的 DolbyAudioCalibrationService.apk 里:
OEM Bridge
└─ onDevicesChanged(Device[]) // IDeviceConnectionListener
↓
DeviceEventHandler.onDevicesChanged()
├─ 读 device.hardwareId.manufacturerName
├─ 读 device.hardwareId.modelName
└─ loadDescriptor(manufacturerName, modelName) → byte[]
↓
CalibrationDirector 侧再把 descriptor 放进 FlexCalibrator$Device
loadDescriptor 实际逻辑(类:com.dolby.android.audio.calibration.DeviceEventHandler):
fileName = manufacturer + "_" + modelName + ".json"
例:OEM + OEM_1ch_WS_L → OEM_OEM_1ch_WS_L.json
在 DEVICE_DESCRIPTOR_PATHS 里依次找,优先:
/vendor/etc/dolby/audio/device_descriptors/<fileName>
找到则 Files.readAllBytes(path)
找不到则 log:"Device descriptor for <manuf> <model> not found."
并跳过该设备("Skipping device ... with invalid device descriptor")
对应 AIDL 字段:
com.dolby.android.audio.deviceconnection.HardwareIdentifiers
- manufacturerName
- modelName
OEM 侧要做的: 上报正确的 manufacturerName / modelName,并保证板子上有
/vendor/etc/dolby/audio/device_descriptors/{manufacturer}_{modelName}.json。
2. FlexConnect 初始化(代码级)
同样是 Dolby 内部调用,OEM 不直接调:
DeviceEventHandler.onDevicesChanged(...)
└─ notifyDeviceChangedListeners()
↓
CalibrationDirector.onDevicesChanged()
├─ getFlexCalibratorDevices() // 含已加载的 descriptor 内容
├─ 组装 List<FlexCalibrator.Device>
└─ mFlexCalibrator.setDevices(list) // ★ FlexConnect 设备初始化入口
↓
FlexCalibratorNative.setDevices(list)
└─ 对每个设备调用 native:
setDevice(deviceId, descriptorJson, connected, ignoreMapping,
isFront, x, y, angle, isFirst, isLast, handle)
↓
libflexcalibrator.dolby.so
接口签名(AIDK):
com.dolby.android.audio.flexcalibrator.FlexCalibrator
boolean setDevices(List<FlexCalibrator.Device> devices)
FlexCalibrator.Device 构造时带:deviceId、descriptor(JSON 字符串内容)、connected / front / position 等。
失败时 Calibration 会打:onDevicesChanged() setDevices failed。
和 MS12 IMs12 的关系:
运行时还有另一套(播放侧 Flexible Rendering):
vendor.dolby.audio.ms12.IMs12
enableFlexibleRendering(boolean)
setFlexibleRendererConfiguration(sconf, dconf)
校准前「按每个设备 connector 初始化」对应的是上面的 FlexCalibrator.setDevices;
IMs12 多在校准产出 sconf / dconf 之后给播放链路用。
3. 音箱连接状态(代码级)
Dolby 侧怎么拿连接状态:
com.dolby.android.audio.deviceconnection.IDeviceConnection
addCallback(IDeviceConnectionListener)
removeCallback()
IDeviceConnectionListener
onDevicesChanged(in Device[] devices)
发现 / 绑定方式(Calibration 内):
Intent action:
com.dolby.android.audio.intent.action.AUDIO_DEVICE_CONNECTED
DeviceEventHandler.connectToDeviceConnectionService()
→ bindService
→ IDeviceConnection.addCallback(...)
→ 立刻收到 onDevicesChanged(规范要求 addCallback 时立即回调)
OEM 侧怎么提供连接状态:
DeviceConnectionBridgeService(OEM)
Manifest 声明 action: AUDIO_DEVICE_CONNECTED
onBind → 返回 IDeviceConnection.Stub
内部:
绑 OemSerialPortRouter
发 AT+GET_RFSTATUS
解析 GET_RFSTATUS_SBAR51_XYZ → 左/右/低音炮
按角色表填 Device[]
hardwareId.manufacturerName = "OEM"
hardwareId.modelName = "OEM_5ch_ISS" / "OEM_1ch_WS_L" / ...
callback.onDevicesChanged(devices)
| 层次 | 接口 / 手段 | 作用 |
|---|---|---|
| 硬件 → App | 串口 AT+GET_RFSTATUS |
物理连没连 |
| App → Dolby | IDeviceConnection.onDevicesChanged |
把连接列表(含 modelName)报给 Calibration |
Dolby 不读 RF;只认 IDeviceConnection 上报的 Device[]。
三件事串成一条
【③ 连接状态 - OEM】
RF/串口 → Bridge 组 Device[](含 modelName)
→ IDeviceConnection.onDevicesChanged()
【① 加载 JSON - Dolby】
DeviceEventHandler.loadDescriptor(manuf, model)
→ 读 /vendor/etc/dolby/audio/device_descriptors/{manuf}_{model}.json
【② 初始化 FlexConnect - Dolby】
CalibrationDirector
→ FlexCalibrator.setDevices(...)
→ native setDevice(deviceId, descriptor, ...)
→ 各设备 connector / FlexConnect 就绪,再开校准
小结(给自己贴墙上)
- 左右身份:RF 位 + Bridge 角色表(①②③),不是 JSON。
- JSON:只描述「这个型号怎么响 / 怎么渲染」,由 Dolby
loadDescriptor按{manufacturer}_{modelName}.json加载。 - FlexConnect 开工:Dolby 内部
FlexCalibrator.setDevices,App 只负责把名单报对、文件预置对。 - 报名单接口 ≠ 初始化接口;搞混就会以为「JSON 决定左右」或「App 要自己调 setDevices」。
记录于 Soundbar / Dolby FlexConnect 联调实践。
评论
还没有评论,来做第一个吧
读完了不评论,作者会以为你在沉思