diff --git a/bumble/profiles/aics.py b/bumble/profiles/aics.py index da3764c9..5930322e 100644 --- a/bumble/profiles/aics.py +++ b/bumble/profiles/aics.py @@ -59,8 +59,8 @@ # Constants # ----------------------------------------------------------------------------- CHANGE_COUNTER_MAX_VALUE = 0xFF -GAIN_SETTINGS_MIN_VALUE = 0 -GAIN_SETTINGS_MAX_VALUE = 255 +GAIN_SETTINGS_MIN_VALUE = -128 +GAIN_SETTINGS_MAX_VALUE = 127 class ErrorCode(utils.OpenIntEnum): @@ -131,13 +131,13 @@ class AudioInputState: attribute: Attribute | None = None def __bytes__(self) -> bytes: - return bytes( - [self.gain_settings, self.mute, self.gain_mode, self.change_counter] + return struct.pack( + "bBBB", self.gain_settings, self.mute, self.gain_mode, self.change_counter ) @classmethod def from_bytes(cls, data: bytes): - gain_settings, mute, gain_mode, change_counter = struct.unpack("BBBB", data) + gain_settings, mute, gain_mode, change_counter = struct.unpack("bBBB", data) return cls(gain_settings, mute, gain_mode, change_counter) def update_gain_settings_unit(self, gain_settings_unit: int) -> None: @@ -172,19 +172,18 @@ class GainSettingsProperties: @classmethod def from_bytes(cls, data: bytes): (gain_settings_unit, gain_settings_minimum, gain_settings_maximum) = ( - struct.unpack('BBB', data) + struct.unpack('Bbb', data) ) return GainSettingsProperties( gain_settings_unit, gain_settings_minimum, gain_settings_maximum ) def __bytes__(self) -> bytes: - return bytes( - [ - self.gain_settings_unit, - self.gain_settings_minimum, - self.gain_settings_maximum, - ] + return struct.pack( + 'Bbb', + self.gain_settings_unit, + self.gain_settings_minimum, + self.gain_settings_maximum, ) @@ -201,7 +200,7 @@ async def on_write(self, connection: Connection, value: bytes) -> None: opcode = AudioInputControlPointOpCode(value[0]) if opcode == AudioInputControlPointOpCode.SET_GAIN_SETTING: - gain_settings_operand = value[2] + gain_settings_operand = struct.unpack_from('b', value, 2)[0] await self._set_gain_settings(connection, gain_settings_operand) elif opcode == AudioInputControlPointOpCode.UNMUTE: await self._unmute(connection) diff --git a/tests/profiles/aics_test.py b/tests/profiles/aics_test.py index 33a8bba1..af4cb390 100644 --- a/tests/profiles/aics_test.py +++ b/tests/profiles/aics_test.py @@ -82,7 +82,7 @@ async def test_init_service(aics_client: AICSServiceProxy): assert ( await aics_client.gain_settings_properties.read_value() == GainSettingsProperties( - gain_settings_unit=1, gain_settings_minimum=0, gain_settings_maximum=255 + gain_settings_unit=1, gain_settings_minimum=-128, gain_settings_maximum=127 ) ) assert await aics_client.audio_input_status.read_value() == ( @@ -179,6 +179,29 @@ async def test_set_gain_setting_when_gain_mode_MANUAL(aics_client: AICSServicePr ) +@pytest.mark.asyncio +async def test_set_negative_gain_setting(aics_client: AICSServiceProxy): + aics_service.audio_input_state.gain_mode = GainMode.MANUAL + change_counter = 0 + gain_settings = -10 + await aics_client.audio_input_control_point.write_value( + bytes( + [ + AudioInputControlPointOpCode.SET_GAIN_SETTING, + change_counter, + gain_settings & 0xFF, + ] + ) + ) + + assert await aics_client.audio_input_state.read_value() == AudioInputState( + gain_settings=gain_settings, + mute=Mute.NOT_MUTED, + gain_mode=GainMode.MANUAL, + change_counter=change_counter, + ) + + @pytest.mark.asyncio async def test_set_gain_setting_when_gain_mode_MANUAL_ONLY( aics_client: AICSServiceProxy,