Make all event emitters async

* Also remove AbortableEventEmitter
This commit is contained in:
Josh Wu
2025-04-12 22:53:32 +08:00
parent 6cecc16519
commit 55801bc2ca
32 changed files with 432 additions and 395 deletions

View File

@@ -48,7 +48,7 @@ from bumble.gatt_adapters import (
UTF8CharacteristicProxyAdapter,
)
from bumble.gatt_client import ProfileServiceProxy, ServiceProxy
from bumble.utils import OpenIntEnum
from bumble import utils
# -----------------------------------------------------------------------------
# Logging
@@ -64,7 +64,7 @@ GAIN_SETTINGS_MIN_VALUE = 0
GAIN_SETTINGS_MAX_VALUE = 255
class ErrorCode(OpenIntEnum):
class ErrorCode(utils.OpenIntEnum):
'''
Cf. 1.6 Application error codes
'''
@@ -76,7 +76,7 @@ class ErrorCode(OpenIntEnum):
GAIN_MODE_CHANGE_NOT_ALLOWED = 0x84
class Mute(OpenIntEnum):
class Mute(utils.OpenIntEnum):
'''
Cf. 2.2.1.2 Mute Field
'''
@@ -86,7 +86,7 @@ class Mute(OpenIntEnum):
DISABLED = 0x02
class GainMode(OpenIntEnum):
class GainMode(utils.OpenIntEnum):
'''
Cf. 2.2.1.3 Gain Mode
'''
@@ -97,7 +97,7 @@ class GainMode(OpenIntEnum):
AUTOMATIC = 0x03
class AudioInputStatus(OpenIntEnum):
class AudioInputStatus(utils.OpenIntEnum):
'''
Cf. 3.4 Audio Input Status
'''
@@ -106,7 +106,7 @@ class AudioInputStatus(OpenIntEnum):
ACTIVE = 0x01
class AudioInputControlPointOpCode(OpenIntEnum):
class AudioInputControlPointOpCode(utils.OpenIntEnum):
'''
Cf. 3.5.1 Audio Input Control Point procedure requirements
'''

View File

@@ -28,7 +28,6 @@ import logging
import struct
from typing import Optional, Sequence, Union
from pyee import EventEmitter
from bumble.att import ATT_Error
from bumble.device import Peer
@@ -42,7 +41,7 @@ from bumble.gatt import (
)
from bumble.gatt_client import CharacteristicProxy, ProfileServiceProxy, ServiceProxy
from bumble.gatt_adapters import SerializableCharacteristicProxyAdapter
from bumble.utils import OpenIntEnum
from bumble import utils
# -----------------------------------------------------------------------------
@@ -60,16 +59,16 @@ logger = logging.getLogger(__name__)
# -----------------------------------------------------------------------------
# Protocol
# -----------------------------------------------------------------------------
class ActionId(OpenIntEnum):
class ActionId(utils.OpenIntEnum):
POSITIVE = 0
NEGATIVE = 1
class AppAttributeId(OpenIntEnum):
class AppAttributeId(utils.OpenIntEnum):
DISPLAY_NAME = 0
class CategoryId(OpenIntEnum):
class CategoryId(utils.OpenIntEnum):
OTHER = 0
INCOMING_CALL = 1
MISSED_CALL = 2
@@ -84,13 +83,13 @@ class CategoryId(OpenIntEnum):
ENTERTAINMENT = 11
class CommandId(OpenIntEnum):
class CommandId(utils.OpenIntEnum):
GET_NOTIFICATION_ATTRIBUTES = 0
GET_APP_ATTRIBUTES = 1
PERFORM_NOTIFICATION_ACTION = 2
class EventId(OpenIntEnum):
class EventId(utils.OpenIntEnum):
NOTIFICATION_ADDED = 0
NOTIFICATION_MODIFIED = 1
NOTIFICATION_REMOVED = 2
@@ -104,7 +103,7 @@ class EventFlags(enum.IntFlag):
NEGATIVE_ACTION = 1 << 4
class NotificationAttributeId(OpenIntEnum):
class NotificationAttributeId(utils.OpenIntEnum):
APP_IDENTIFIER = 0
TITLE = 1
SUBTITLE = 2
@@ -156,7 +155,7 @@ class Notification:
)
class ErrorCode(OpenIntEnum):
class ErrorCode(utils.OpenIntEnum):
UNKNOWN_COMMAND = 0xA0
INVALID_COMMAND = 0xA1
INVALID_PARAMETER = 0xA2
@@ -243,7 +242,7 @@ class AncsProxy(ProfileServiceProxy):
)
class AncsClient(EventEmitter):
class AncsClient(utils.EventEmitter):
_expected_response_command_id: Optional[CommandId]
_expected_response_notification_uid: Optional[int]
_expected_response_app_identifier: Optional[str]

View File

@@ -23,6 +23,7 @@ import logging
import struct
from typing import Any, Dict, List, Optional, Sequence, Tuple, Type, Union
from bumble import utils
from bumble import colors
from bumble.profiles.bap import CodecSpecificConfiguration
from bumble.profiles import le_audio
@@ -343,8 +344,10 @@ class AseStateMachine(gatt.Characteristic):
and cis_id == self.cis_id
and self.state == self.State.ENABLING
):
acl_connection.abort_on(
'flush', self.service.device.accept_cis_request(cis_handle)
utils.cancel_on_event(
acl_connection,
'flush',
self.service.device.accept_cis_request(cis_handle),
)
def on_cis_establishment(self, cis_link: device.CisLink) -> None:
@@ -361,7 +364,9 @@ class AseStateMachine(gatt.Characteristic):
self.state = self.State.STREAMING
await self.service.device.notify_subscribers(self, self.value)
cis_link.acl_connection.abort_on('flush', post_cis_established())
utils.cancel_on_event(
cis_link.acl_connection, 'flush', post_cis_established()
)
self.cis_link = cis_link
def on_cis_disconnection(self, _reason) -> None:
@@ -509,7 +514,7 @@ class AseStateMachine(gatt.Characteristic):
self.state = self.State.IDLE
await self.service.device.notify_subscribers(self, self.value)
self.service.device.abort_on('flush', remove_cis_async())
utils.cancel_on_event(self.service.device, 'flush', remove_cis_async())
return (AseResponseCode.SUCCESS, AseReasonCode.NONE)
@property
@@ -691,7 +696,8 @@ class AudioStreamControlService(gatt.TemplateService):
control_point_notification = bytes(
[operation.op_code, len(responses)]
) + b''.join(map(bytes, responses))
self.device.abort_on(
utils.cancel_on_event(
self.device,
'flush',
self.device.notify_subscribers(
self.ase_control_point, control_point_notification
@@ -700,7 +706,8 @@ class AudioStreamControlService(gatt.TemplateService):
for ase_id, *_ in responses:
if ase := self.ase_state_machines.get(ase_id):
self.device.abort_on(
utils.cancel_on_event(
self.device,
'flush',
self.device.notify_subscribers(ase, ase.value),
)

View File

@@ -25,14 +25,14 @@ from typing import Any, Dict, List, Optional, Set, Union
from bumble import att, gatt, gatt_adapters, gatt_client
from bumble.core import InvalidArgumentError, InvalidStateError
from bumble.device import Device, Connection
from bumble.utils import AsyncRunner, OpenIntEnum
from bumble import utils
from bumble.hci import Address
# -----------------------------------------------------------------------------
# Constants
# -----------------------------------------------------------------------------
class ErrorCode(OpenIntEnum):
class ErrorCode(utils.OpenIntEnum):
'''See Hearing Access Service 2.4. Attribute Profile error codes.'''
INVALID_OPCODE = 0x80
@@ -42,7 +42,7 @@ class ErrorCode(OpenIntEnum):
INVALID_PARAMETERS_LENGTH = 0x84
class HearingAidType(OpenIntEnum):
class HearingAidType(utils.OpenIntEnum):
'''See Hearing Access Service 3.1. Hearing Aid Features.'''
BINAURAL_HEARING_AID = 0b00
@@ -50,35 +50,35 @@ class HearingAidType(OpenIntEnum):
BANDED_HEARING_AID = 0b10
class PresetSynchronizationSupport(OpenIntEnum):
class PresetSynchronizationSupport(utils.OpenIntEnum):
'''See Hearing Access Service 3.1. Hearing Aid Features.'''
PRESET_SYNCHRONIZATION_IS_NOT_SUPPORTED = 0b0
PRESET_SYNCHRONIZATION_IS_SUPPORTED = 0b1
class IndependentPresets(OpenIntEnum):
class IndependentPresets(utils.OpenIntEnum):
'''See Hearing Access Service 3.1. Hearing Aid Features.'''
IDENTICAL_PRESET_RECORD = 0b0
DIFFERENT_PRESET_RECORD = 0b1
class DynamicPresets(OpenIntEnum):
class DynamicPresets(utils.OpenIntEnum):
'''See Hearing Access Service 3.1. Hearing Aid Features.'''
PRESET_RECORDS_DOES_NOT_CHANGE = 0b0
PRESET_RECORDS_MAY_CHANGE = 0b1
class WritablePresetsSupport(OpenIntEnum):
class WritablePresetsSupport(utils.OpenIntEnum):
'''See Hearing Access Service 3.1. Hearing Aid Features.'''
WRITABLE_PRESET_RECORDS_NOT_SUPPORTED = 0b0
WRITABLE_PRESET_RECORDS_SUPPORTED = 0b1
class HearingAidPresetControlPointOpcode(OpenIntEnum):
class HearingAidPresetControlPointOpcode(utils.OpenIntEnum):
'''See Hearing Access Service 3.3.1 Hearing Aid Preset Control Point operation requirements.'''
# fmt: off
@@ -130,7 +130,7 @@ def HearingAidFeatures_from_bytes(data: int) -> HearingAidFeatures:
class PresetChangedOperation:
'''See Hearing Access Service 3.2.2.2. Preset Changed operation.'''
class ChangeId(OpenIntEnum):
class ChangeId(utils.OpenIntEnum):
# fmt: off
GENERIC_UPDATE = 0x00
PRESET_RECORD_DELETED = 0x01
@@ -190,11 +190,11 @@ class PresetRecord:
@dataclass
class Property:
class Writable(OpenIntEnum):
class Writable(utils.OpenIntEnum):
CANNOT_BE_WRITTEN = 0b0
CAN_BE_WRITTEN = 0b1
class IsAvailable(OpenIntEnum):
class IsAvailable(utils.OpenIntEnum):
IS_UNAVAILABLE = 0b0
IS_AVAILABLE = 0b1
@@ -333,7 +333,7 @@ class HearingAccessService(gatt.TemplateService):
# Update the active preset index if needed
await self.notify_active_preset_for_connection(connection)
connection.abort_on('disconnection', on_connection_async())
utils.cancel_on_event(connection, 'disconnection', on_connection_async())
def _on_read_active_preset_index(
self, __connection__: Optional[Connection]
@@ -382,7 +382,7 @@ class HearingAccessService(gatt.TemplateService):
if len(presets) == 0:
raise att.ATT_Error(att.ErrorCode.OUT_OF_RANGE)
AsyncRunner.spawn(self._read_preset_response(connection, presets))
utils.AsyncRunner.spawn(self._read_preset_response(connection, presets))
async def _read_preset_response(
self, connection: Connection, presets: List[PresetRecord]

View File

@@ -23,6 +23,7 @@ import enum
from typing import Optional, Sequence
from bumble import att
from bumble import utils
from bumble import device
from bumble import gatt
from bumble import gatt_adapters
@@ -160,7 +161,8 @@ class VolumeControlService(gatt.TemplateService):
handler = getattr(self, '_on_' + opcode.name.lower())
if handler(*value[2:]):
self.change_counter = (self.change_counter + 1) % 256
connection.abort_on(
utils.cancel_on_event(
connection,
'disconnection',
connection.device.notify_subscribers(attribute=self.volume_state),
)

View File

@@ -38,7 +38,7 @@ from bumble.gatt_adapters import (
UTF8CharacteristicProxyAdapter,
)
from bumble.gatt_client import ProfileServiceProxy, ServiceProxy
from bumble.utils import OpenIntEnum
from bumble import utils
from bumble.profiles.bap import AudioLocation
# -----------------------------------------------------------------------------
@@ -50,11 +50,11 @@ MAX_VOLUME_OFFSET = 255
CHANGE_COUNTER_MAX_VALUE = 0xFF
class SetVolumeOffsetOpCode(OpenIntEnum):
class SetVolumeOffsetOpCode(utils.OpenIntEnum):
SET_VOLUME_OFFSET = 0x01
class ErrorCode(OpenIntEnum):
class ErrorCode(utils.OpenIntEnum):
"""
See Volume Offset Control Service 1.6. Application error codes.
"""