mirror of
https://github.com/d4rken-org/capod.git
synced 2026-09-15 02:36:12 -04:00
fix(aap): Correct EndCallMuteMic mapping based on real-device behavior
Swap the logical mapping for `EndCallMuteMic` settings to align with hardware states observed on AirPods Pro devices. Updated session tests for Pro 1, 2, and 3 to reflect the corrected protocol behavior.
This commit is contained in:
+16
-17
@@ -10,7 +10,6 @@ import eu.darken.capod.pods.core.apple.aap.protocol.DefaultAapDeviceProfile
|
||||
import io.kotest.assertions.throwables.shouldThrow
|
||||
import io.kotest.matchers.collections.shouldContainExactly
|
||||
import io.kotest.matchers.nulls.shouldBeNull
|
||||
import io.kotest.matchers.nulls.shouldNotBeNull
|
||||
import io.kotest.matchers.shouldBe
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
@@ -132,7 +131,7 @@ class DefaultAapDeviceProfileTest : BaseAapSessionTest() {
|
||||
fun `round-trip all modes`() {
|
||||
for (mode in AapSetting.AncMode.Value.entries) {
|
||||
val encoded = profile.encodeCommand(AapCommand.SetAncMode(mode))
|
||||
val decoded = decodeSetting<AapSetting.AncMode>(AapMessage.Companion.parse(encoded)!!)
|
||||
val decoded = decodeSetting<AapSetting.AncMode>(AapMessage.parse(encoded)!!)
|
||||
decoded.current shouldBe mode
|
||||
}
|
||||
}
|
||||
@@ -166,7 +165,7 @@ class DefaultAapDeviceProfileTest : BaseAapSessionTest() {
|
||||
fun `round-trip all values`() {
|
||||
for (v in AapSetting.PressSpeed.Value.entries) {
|
||||
val encoded = profile.encodeCommand(AapCommand.SetPressSpeed(v))
|
||||
decodeSetting<AapSetting.PressSpeed>(AapMessage.Companion.parse(encoded)!!).value shouldBe v
|
||||
decodeSetting<AapSetting.PressSpeed>(AapMessage.parse(encoded)!!).value shouldBe v
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,7 +183,7 @@ class DefaultAapDeviceProfileTest : BaseAapSessionTest() {
|
||||
fun `round-trip all values`() {
|
||||
for (v in AapSetting.PressHoldDuration.Value.entries) {
|
||||
val encoded = profile.encodeCommand(AapCommand.SetPressHoldDuration(v))
|
||||
decodeSetting<AapSetting.PressHoldDuration>(AapMessage.Companion.parse(encoded)!!).value shouldBe v
|
||||
decodeSetting<AapSetting.PressHoldDuration>(AapMessage.parse(encoded)!!).value shouldBe v
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -224,7 +223,7 @@ class DefaultAapDeviceProfileTest : BaseAapSessionTest() {
|
||||
fun `round-trip all values`() {
|
||||
for (v in AapSetting.VolumeSwipeLength.Value.entries) {
|
||||
val encoded = profile.encodeCommand(AapCommand.SetVolumeSwipeLength(v))
|
||||
decodeSetting<AapSetting.VolumeSwipeLength>(AapMessage.Companion.parse(encoded)!!).value shouldBe v
|
||||
decodeSetting<AapSetting.VolumeSwipeLength>(AapMessage.parse(encoded)!!).value shouldBe v
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -259,7 +258,7 @@ class DefaultAapDeviceProfileTest : BaseAapSessionTest() {
|
||||
@Test fun `encode decode round-trip`() {
|
||||
for (ui in listOf(0, 25, 50, 75, 100)) {
|
||||
val encoded = profile.encodeCommand(AapCommand.SetAdaptiveAudioNoise(ui))
|
||||
decodeSetting<AapSetting.AdaptiveAudioNoise>(AapMessage.Companion.parse(encoded)!!).level shouldBe ui
|
||||
decodeSetting<AapSetting.AdaptiveAudioNoise>(AapMessage.parse(encoded)!!).level shouldBe ui
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -280,7 +279,7 @@ class DefaultAapDeviceProfileTest : BaseAapSessionTest() {
|
||||
0x04, 0x00, 0x04, 0x00,
|
||||
0x09, 0x00,
|
||||
0x24, 0x20,
|
||||
0x02,
|
||||
0x03,
|
||||
0x00, 0x00,
|
||||
)
|
||||
}
|
||||
@@ -297,7 +296,7 @@ class DefaultAapDeviceProfileTest : BaseAapSessionTest() {
|
||||
0x04, 0x00, 0x04, 0x00,
|
||||
0x09, 0x00,
|
||||
0x24, 0x20,
|
||||
0x03,
|
||||
0x02,
|
||||
0x00, 0x00,
|
||||
)
|
||||
}
|
||||
@@ -342,22 +341,22 @@ class DefaultAapDeviceProfileTest : BaseAapSessionTest() {
|
||||
@Test
|
||||
fun `decode compact format 0x20 combined 0x02`() {
|
||||
val ecm = decodeSetting<AapSetting.EndCallMuteMic>(aapMessage("04 00 04 00 09 00 24 20 02 00 00"))
|
||||
ecm.muteMic shouldBe AapSetting.EndCallMuteMic.MuteMicMode.SINGLE_PRESS
|
||||
ecm.endCall shouldBe AapSetting.EndCallMuteMic.EndCallMode.DOUBLE_PRESS
|
||||
ecm.muteMic shouldBe AapSetting.EndCallMuteMic.MuteMicMode.DOUBLE_PRESS
|
||||
ecm.endCall shouldBe AapSetting.EndCallMuteMic.EndCallMode.SINGLE_PRESS
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `decode compact format 0x20 combined 0x03`() {
|
||||
val ecm = decodeSetting<AapSetting.EndCallMuteMic>(aapMessage("04 00 04 00 09 00 24 20 03 00 00"))
|
||||
ecm.muteMic shouldBe AapSetting.EndCallMuteMic.MuteMicMode.DOUBLE_PRESS
|
||||
ecm.endCall shouldBe AapSetting.EndCallMuteMic.EndCallMode.SINGLE_PRESS
|
||||
ecm.muteMic shouldBe AapSetting.EndCallMuteMic.MuteMicMode.SINGLE_PRESS
|
||||
ecm.endCall shouldBe AapSetting.EndCallMuteMic.EndCallMode.DOUBLE_PRESS
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `decode compact format subtype 0x00 from real Pro 3`() {
|
||||
val ecm = decodeSetting<AapSetting.EndCallMuteMic>(aapMessage("04 00 04 00 09 00 24 00 03 00 00"))
|
||||
ecm.muteMic shouldBe AapSetting.EndCallMuteMic.MuteMicMode.DOUBLE_PRESS
|
||||
ecm.endCall shouldBe AapSetting.EndCallMuteMic.EndCallMode.SINGLE_PRESS
|
||||
ecm.muteMic shouldBe AapSetting.EndCallMuteMic.MuteMicMode.SINGLE_PRESS
|
||||
ecm.endCall shouldBe AapSetting.EndCallMuteMic.EndCallMode.DOUBLE_PRESS
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -462,7 +461,7 @@ class DefaultAapDeviceProfileTest : BaseAapSessionTest() {
|
||||
val enc = ByteArray(16) { 0x22.toByte() }
|
||||
val payload = byteArrayOf(0x02, 0x01, 0x00, 16, 0x00, *irk, 0x04, 0x00, 16, 0x00, *enc)
|
||||
val raw = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x31, 0x00) + payload
|
||||
val result = profile.decodePrivateKeyResponse(AapMessage.Companion.parse(raw)!!)!!
|
||||
val result = profile.decodePrivateKeyResponse(AapMessage.parse(raw)!!)!!
|
||||
result.irk shouldBe irk
|
||||
result.encKey shouldBe enc
|
||||
}
|
||||
@@ -471,7 +470,7 @@ class DefaultAapDeviceProfileTest : BaseAapSessionTest() {
|
||||
fun `decode response with only IRK`() {
|
||||
val irk = ByteArray(16) { 0xAA.toByte() }
|
||||
val raw = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x31, 0x00, 0x01, 0x01, 0x00, 16, 0x00, *irk)
|
||||
val result = profile.decodePrivateKeyResponse(AapMessage.Companion.parse(raw)!!)!!
|
||||
val result = profile.decodePrivateKeyResponse(AapMessage.parse(raw)!!)!!
|
||||
result.irk shouldBe irk
|
||||
result.encKey.shouldBeNull()
|
||||
}
|
||||
@@ -573,4 +572,4 @@ class DefaultAapDeviceProfileTest : BaseAapSessionTest() {
|
||||
@Test fun `unknown setting ID returns null`() { profile.decodeSetting(settingsMessage(0x7F, 0x01)).shouldBeNull() }
|
||||
@Test fun `non-settings command returns null`() { profile.decodeSetting(aapMessage("04 00 04 00 1D 00 01 02 03 04")).shouldBeNull() }
|
||||
@Test fun `payload too short returns null`() { profile.decodeSetting(aapMessage("04 00 04 00 09 00 0D")).shouldBeNull() }
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -142,8 +142,8 @@ class AirPodsPro2UsbcAapSessionTest : BaseAapSessionTest() {
|
||||
|
||||
@Test fun `end call mute mic - subtype 0x00`() {
|
||||
decodeSetting<AapSetting.EndCallMuteMic>("04 00 04 00 09 00 24 00 03 00 00").let {
|
||||
it.muteMic shouldBe AapSetting.EndCallMuteMic.MuteMicMode.DOUBLE_PRESS
|
||||
it.endCall shouldBe AapSetting.EndCallMuteMic.EndCallMode.SINGLE_PRESS
|
||||
it.muteMic shouldBe AapSetting.EndCallMuteMic.MuteMicMode.SINGLE_PRESS
|
||||
it.endCall shouldBe AapSetting.EndCallMuteMic.EndCallMode.DOUBLE_PRESS
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ class AirPodsPro2UsbcAapSessionTest : BaseAapSessionTest() {
|
||||
|
||||
@Test
|
||||
fun `unknown settings IDs return null`() {
|
||||
val unknownIds = listOf(0x29, 0x2C, 0x2F, 0x33, 0x3E)
|
||||
val unknownIds = listOf(0x29, 0x2C, 0x2F, 0x33)
|
||||
for (id in unknownIds) {
|
||||
profile.decodeSetting(settingsMessage(id, 0x02)).shouldBeNull()
|
||||
}
|
||||
|
||||
+3
-3
@@ -134,7 +134,7 @@ class AirPodsPro3AapSessionTest : BaseAapSessionTest() {
|
||||
}
|
||||
|
||||
@Test fun `end call mute mic - subtype 0x00`() {
|
||||
decodeSetting<AapSetting.EndCallMuteMic>("04 00 04 00 09 00 24 00 03 00 00").let { it.muteMic shouldBe AapSetting.EndCallMuteMic.MuteMicMode.DOUBLE_PRESS; it.endCall shouldBe AapSetting.EndCallMuteMic.EndCallMode.SINGLE_PRESS }
|
||||
decodeSetting<AapSetting.EndCallMuteMic>("04 00 04 00 09 00 24 00 03 00 00").let { it.muteMic shouldBe AapSetting.EndCallMuteMic.MuteMicMode.SINGLE_PRESS; it.endCall shouldBe AapSetting.EndCallMuteMic.EndCallMode.DOUBLE_PRESS }
|
||||
}
|
||||
|
||||
@Test fun `conversational awareness OFF`() {
|
||||
@@ -237,10 +237,10 @@ class AirPodsPro3AapSessionTest : BaseAapSessionTest() {
|
||||
|
||||
@Test
|
||||
fun `unknown settings IDs return null`() {
|
||||
val unknownIds = listOf(0x29, 0x2C, 0x2F, 0x33, 0x30, 0x3E, 0x37, 0x38, 0x3B)
|
||||
val unknownIds = listOf(0x29, 0x2C, 0x2F, 0x33, 0x30, 0x37, 0x38, 0x3B)
|
||||
for (id in unknownIds) {
|
||||
profile.decodeSetting(settingsMessage(id, 0x01)).shouldBeNull()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -137,8 +137,8 @@ class AirPodsProAapSessionTest : BaseAapSessionTest() {
|
||||
|
||||
@Test fun `end call mute mic - subtype 0x20`() {
|
||||
decodeSetting<AapSetting.EndCallMuteMic>("04 00 04 00 09 00 24 20 03 00 00").let {
|
||||
it.muteMic shouldBe AapSetting.EndCallMuteMic.MuteMicMode.DOUBLE_PRESS
|
||||
it.endCall shouldBe AapSetting.EndCallMuteMic.EndCallMode.SINGLE_PRESS
|
||||
it.muteMic shouldBe AapSetting.EndCallMuteMic.MuteMicMode.SINGLE_PRESS
|
||||
it.endCall shouldBe AapSetting.EndCallMuteMic.EndCallMode.DOUBLE_PRESS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user