Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 12 additions & 13 deletions bumble/profiles/aics.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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,
)


Expand All @@ -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)
Expand Down
25 changes: 24 additions & 1 deletion tests/profiles/aics_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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() == (
Expand Down Expand Up @@ -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,
Expand Down
Loading