mirror of
https://github.com/google/bumble.git
synced 2026-05-08 03:58:01 +00:00
Declare emitted events as constants
This commit is contained in:
190
bumble/avdtp.py
190
bumble/avdtp.py
@@ -896,7 +896,7 @@ class Set_Configuration_Reject(Message):
|
||||
self.service_category = self.payload[0]
|
||||
self.error_code = self.payload[1]
|
||||
|
||||
def __init__(self, service_category, error_code):
|
||||
def __init__(self, error_code: int, service_category: int = 0) -> None:
|
||||
super().__init__(payload=bytes([service_category, error_code]))
|
||||
self.service_category = service_category
|
||||
self.error_code = error_code
|
||||
@@ -1132,6 +1132,14 @@ class Security_Control_Command(Message):
|
||||
See Bluetooth AVDTP spec - 8.17.1 Security Control Command
|
||||
'''
|
||||
|
||||
def init_from_payload(self):
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
self.acp_seid = self.payload[0] >> 2
|
||||
self.data = self.payload[1:]
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.to_string([f'ACP_SEID: {self.acp_seid}', f'data: {self.data}'])
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@Message.subclass
|
||||
@@ -1200,6 +1208,9 @@ class Protocol(utils.EventEmitter):
|
||||
transaction_results: List[Optional[asyncio.Future[Message]]]
|
||||
channel_connector: Callable[[], Awaitable[l2cap.ClassicChannel]]
|
||||
|
||||
EVENT_OPEN = "open"
|
||||
EVENT_CLOSE = "close"
|
||||
|
||||
class PacketType(enum.IntEnum):
|
||||
SINGLE_PACKET = 0
|
||||
START_PACKET = 1
|
||||
@@ -1239,8 +1250,8 @@ class Protocol(utils.EventEmitter):
|
||||
|
||||
# Register to receive PDUs from the channel
|
||||
l2cap_channel.sink = self.on_pdu
|
||||
l2cap_channel.on('open', self.on_l2cap_channel_open)
|
||||
l2cap_channel.on('close', self.on_l2cap_channel_close)
|
||||
l2cap_channel.on(l2cap_channel.EVENT_OPEN, self.on_l2cap_channel_open)
|
||||
l2cap_channel.on(l2cap_channel.EVENT_CLOSE, self.on_l2cap_channel_close)
|
||||
|
||||
def get_local_endpoint_by_seid(self, seid: int) -> Optional[LocalStreamEndPoint]:
|
||||
if 0 < seid <= len(self.local_endpoints):
|
||||
@@ -1410,20 +1421,20 @@ class Protocol(utils.EventEmitter):
|
||||
self.transaction_results[transaction_label] = None
|
||||
self.transaction_semaphore.release()
|
||||
|
||||
def on_l2cap_connection(self, channel):
|
||||
def on_l2cap_connection(self, channel: l2cap.ClassicChannel) -> None:
|
||||
# Forward the channel to the endpoint that's expecting it
|
||||
if self.channel_acceptor is None:
|
||||
logger.warning(color('!!! l2cap connection with no acceptor', 'red'))
|
||||
return
|
||||
self.channel_acceptor.on_l2cap_connection(channel)
|
||||
|
||||
def on_l2cap_channel_open(self):
|
||||
def on_l2cap_channel_open(self) -> None:
|
||||
logger.debug(color('<<< L2CAP channel open', 'magenta'))
|
||||
self.emit('open')
|
||||
self.emit(self.EVENT_OPEN)
|
||||
|
||||
def on_l2cap_channel_close(self):
|
||||
def on_l2cap_channel_close(self) -> None:
|
||||
logger.debug(color('<<< L2CAP channel close', 'magenta'))
|
||||
self.emit('close')
|
||||
self.emit(self.EVENT_CLOSE)
|
||||
|
||||
def send_message(self, transaction_label: int, message: Message) -> None:
|
||||
logger.debug(
|
||||
@@ -1541,28 +1552,34 @@ class Protocol(utils.EventEmitter):
|
||||
async def abort(self, seid: int) -> Abort_Response:
|
||||
return await self.send_command(Abort_Command(seid))
|
||||
|
||||
def on_discover_command(self, _command):
|
||||
def on_discover_command(self, command: Discover_Command) -> Optional[Message]:
|
||||
endpoint_infos = [
|
||||
EndPointInfo(endpoint.seid, 0, endpoint.media_type, endpoint.tsep)
|
||||
for endpoint in self.local_endpoints
|
||||
]
|
||||
return Discover_Response(endpoint_infos)
|
||||
|
||||
def on_get_capabilities_command(self, command):
|
||||
def on_get_capabilities_command(
|
||||
self, command: Get_Capabilities_Command
|
||||
) -> Optional[Message]:
|
||||
endpoint = self.get_local_endpoint_by_seid(command.acp_seid)
|
||||
if endpoint is None:
|
||||
return Get_Capabilities_Reject(AVDTP_BAD_ACP_SEID_ERROR)
|
||||
|
||||
return Get_Capabilities_Response(endpoint.capabilities)
|
||||
|
||||
def on_get_all_capabilities_command(self, command):
|
||||
def on_get_all_capabilities_command(
|
||||
self, command: Get_All_Capabilities_Command
|
||||
) -> Optional[Message]:
|
||||
endpoint = self.get_local_endpoint_by_seid(command.acp_seid)
|
||||
if endpoint is None:
|
||||
return Get_All_Capabilities_Reject(AVDTP_BAD_ACP_SEID_ERROR)
|
||||
|
||||
return Get_All_Capabilities_Response(endpoint.capabilities)
|
||||
|
||||
def on_set_configuration_command(self, command):
|
||||
def on_set_configuration_command(
|
||||
self, command: Set_Configuration_Command
|
||||
) -> Optional[Message]:
|
||||
endpoint = self.get_local_endpoint_by_seid(command.acp_seid)
|
||||
if endpoint is None:
|
||||
return Set_Configuration_Reject(AVDTP_BAD_ACP_SEID_ERROR)
|
||||
@@ -1578,7 +1595,9 @@ class Protocol(utils.EventEmitter):
|
||||
result = stream.on_set_configuration_command(command.capabilities)
|
||||
return result or Set_Configuration_Response()
|
||||
|
||||
def on_get_configuration_command(self, command):
|
||||
def on_get_configuration_command(
|
||||
self, command: Get_Configuration_Command
|
||||
) -> Optional[Message]:
|
||||
endpoint = self.get_local_endpoint_by_seid(command.acp_seid)
|
||||
if endpoint is None:
|
||||
return Get_Configuration_Reject(AVDTP_BAD_ACP_SEID_ERROR)
|
||||
@@ -1587,7 +1606,7 @@ class Protocol(utils.EventEmitter):
|
||||
|
||||
return endpoint.stream.on_get_configuration_command()
|
||||
|
||||
def on_reconfigure_command(self, command):
|
||||
def on_reconfigure_command(self, command: Reconfigure_Command) -> Optional[Message]:
|
||||
endpoint = self.get_local_endpoint_by_seid(command.acp_seid)
|
||||
if endpoint is None:
|
||||
return Reconfigure_Reject(0, AVDTP_BAD_ACP_SEID_ERROR)
|
||||
@@ -1597,7 +1616,7 @@ class Protocol(utils.EventEmitter):
|
||||
result = endpoint.stream.on_reconfigure_command(command.capabilities)
|
||||
return result or Reconfigure_Response()
|
||||
|
||||
def on_open_command(self, command):
|
||||
def on_open_command(self, command: Open_Command) -> Optional[Message]:
|
||||
endpoint = self.get_local_endpoint_by_seid(command.acp_seid)
|
||||
if endpoint is None:
|
||||
return Open_Reject(AVDTP_BAD_ACP_SEID_ERROR)
|
||||
@@ -1607,25 +1626,26 @@ class Protocol(utils.EventEmitter):
|
||||
result = endpoint.stream.on_open_command()
|
||||
return result or Open_Response()
|
||||
|
||||
def on_start_command(self, command):
|
||||
def on_start_command(self, command: Start_Command) -> Optional[Message]:
|
||||
for seid in command.acp_seids:
|
||||
endpoint = self.get_local_endpoint_by_seid(seid)
|
||||
if endpoint is None:
|
||||
return Start_Reject(seid, AVDTP_BAD_ACP_SEID_ERROR)
|
||||
if endpoint.stream is None:
|
||||
return Start_Reject(AVDTP_BAD_STATE_ERROR)
|
||||
return Start_Reject(seid, AVDTP_BAD_STATE_ERROR)
|
||||
|
||||
# Start all streams
|
||||
# TODO: deal with partial failures
|
||||
for seid in command.acp_seids:
|
||||
endpoint = self.get_local_endpoint_by_seid(seid)
|
||||
result = endpoint.stream.on_start_command()
|
||||
if result is not None:
|
||||
if not endpoint or not endpoint.stream:
|
||||
raise InvalidStateError("Should already be checked!")
|
||||
if (result := endpoint.stream.on_start_command()) is not None:
|
||||
return result
|
||||
|
||||
return Start_Response()
|
||||
|
||||
def on_suspend_command(self, command):
|
||||
def on_suspend_command(self, command: Suspend_Command) -> Optional[Message]:
|
||||
for seid in command.acp_seids:
|
||||
endpoint = self.get_local_endpoint_by_seid(seid)
|
||||
if endpoint is None:
|
||||
@@ -1637,13 +1657,14 @@ class Protocol(utils.EventEmitter):
|
||||
# TODO: deal with partial failures
|
||||
for seid in command.acp_seids:
|
||||
endpoint = self.get_local_endpoint_by_seid(seid)
|
||||
result = endpoint.stream.on_suspend_command()
|
||||
if result is not None:
|
||||
if not endpoint or not endpoint.stream:
|
||||
raise InvalidStateError("Should already be checked!")
|
||||
if (result := endpoint.stream.on_suspend_command()) is not None:
|
||||
return result
|
||||
|
||||
return Suspend_Response()
|
||||
|
||||
def on_close_command(self, command):
|
||||
def on_close_command(self, command: Close_Command) -> Optional[Message]:
|
||||
endpoint = self.get_local_endpoint_by_seid(command.acp_seid)
|
||||
if endpoint is None:
|
||||
return Close_Reject(AVDTP_BAD_ACP_SEID_ERROR)
|
||||
@@ -1653,7 +1674,7 @@ class Protocol(utils.EventEmitter):
|
||||
result = endpoint.stream.on_close_command()
|
||||
return result or Close_Response()
|
||||
|
||||
def on_abort_command(self, command):
|
||||
def on_abort_command(self, command: Abort_Command) -> Optional[Message]:
|
||||
endpoint = self.get_local_endpoint_by_seid(command.acp_seid)
|
||||
if endpoint is None or endpoint.stream is None:
|
||||
return Abort_Response()
|
||||
@@ -1661,15 +1682,17 @@ class Protocol(utils.EventEmitter):
|
||||
endpoint.stream.on_abort_command()
|
||||
return Abort_Response()
|
||||
|
||||
def on_security_control_command(self, command):
|
||||
def on_security_control_command(
|
||||
self, command: Security_Control_Command
|
||||
) -> Optional[Message]:
|
||||
endpoint = self.get_local_endpoint_by_seid(command.acp_seid)
|
||||
if endpoint is None:
|
||||
return Security_Control_Reject(AVDTP_BAD_ACP_SEID_ERROR)
|
||||
|
||||
result = endpoint.on_security_control_command(command.payload)
|
||||
result = endpoint.on_security_control_command(command.data)
|
||||
return result or Security_Control_Response()
|
||||
|
||||
def on_delayreport_command(self, command):
|
||||
def on_delayreport_command(self, command: DelayReport_Command) -> Optional[Message]:
|
||||
endpoint = self.get_local_endpoint_by_seid(command.acp_seid)
|
||||
if endpoint is None:
|
||||
return DelayReport_Reject(AVDTP_BAD_ACP_SEID_ERROR)
|
||||
@@ -1682,6 +1705,8 @@ class Protocol(utils.EventEmitter):
|
||||
class Listener(utils.EventEmitter):
|
||||
servers: Dict[int, Protocol]
|
||||
|
||||
EVENT_CONNECTION = "connection"
|
||||
|
||||
@staticmethod
|
||||
def create_registrar(device: device.Device):
|
||||
warnings.warn("Please use Listener.for_device()", DeprecationWarning)
|
||||
@@ -1716,7 +1741,7 @@ class Listener(utils.EventEmitter):
|
||||
l2cap_server = device.create_l2cap_server(
|
||||
spec=l2cap.ClassicChannelSpec(psm=AVDTP_PSM)
|
||||
)
|
||||
l2cap_server.on('connection', listener.on_l2cap_connection)
|
||||
l2cap_server.on(l2cap_server.EVENT_CONNECTION, listener.on_l2cap_connection)
|
||||
return listener
|
||||
|
||||
def on_l2cap_connection(self, channel: l2cap.ClassicChannel) -> None:
|
||||
@@ -1732,14 +1757,14 @@ class Listener(utils.EventEmitter):
|
||||
logger.debug('setting up new Protocol for the connection')
|
||||
server = Protocol(channel, self.version)
|
||||
self.set_server(channel.connection, server)
|
||||
self.emit('connection', server)
|
||||
self.emit(self.EVENT_CONNECTION, server)
|
||||
|
||||
def on_channel_close():
|
||||
logger.debug('removing Protocol for the connection')
|
||||
self.remove_server(channel.connection)
|
||||
|
||||
channel.on('open', on_channel_open)
|
||||
channel.on('close', on_channel_close)
|
||||
channel.on(channel.EVENT_OPEN, on_channel_open)
|
||||
channel.on(channel.EVENT_CLOSE, on_channel_close)
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@@ -1788,6 +1813,7 @@ class Stream:
|
||||
)
|
||||
|
||||
async def start(self) -> None:
|
||||
"""[Source] Start streaming."""
|
||||
# Auto-open if needed
|
||||
if self.state == AVDTP_CONFIGURED_STATE:
|
||||
await self.open()
|
||||
@@ -1804,6 +1830,7 @@ class Stream:
|
||||
self.change_state(AVDTP_STREAMING_STATE)
|
||||
|
||||
async def stop(self) -> None:
|
||||
"""[Source] Stop streaming and transit to OPEN state."""
|
||||
if self.state != AVDTP_STREAMING_STATE:
|
||||
raise InvalidStateError('current state is not STREAMING')
|
||||
|
||||
@@ -1816,6 +1843,7 @@ class Stream:
|
||||
self.change_state(AVDTP_OPEN_STATE)
|
||||
|
||||
async def close(self) -> None:
|
||||
"""[Source] Close channel and transit to IDLE state."""
|
||||
if self.state not in (AVDTP_OPEN_STATE, AVDTP_STREAMING_STATE):
|
||||
raise InvalidStateError('current state is not OPEN or STREAMING')
|
||||
|
||||
@@ -1847,7 +1875,7 @@ class Stream:
|
||||
self.change_state(AVDTP_CONFIGURED_STATE)
|
||||
return None
|
||||
|
||||
def on_get_configuration_command(self, configuration):
|
||||
def on_get_configuration_command(self):
|
||||
if self.state not in (
|
||||
AVDTP_CONFIGURED_STATE,
|
||||
AVDTP_OPEN_STATE,
|
||||
@@ -1855,7 +1883,7 @@ class Stream:
|
||||
):
|
||||
return Get_Configuration_Reject(AVDTP_BAD_STATE_ERROR)
|
||||
|
||||
return self.local_endpoint.on_get_configuration_command(configuration)
|
||||
return self.local_endpoint.on_get_configuration_command()
|
||||
|
||||
def on_reconfigure_command(self, configuration):
|
||||
if self.state != AVDTP_OPEN_STATE:
|
||||
@@ -1935,20 +1963,20 @@ class Stream:
|
||||
# Wait for the RTP channel to be closed
|
||||
self.change_state(AVDTP_ABORTING_STATE)
|
||||
|
||||
def on_l2cap_connection(self, channel):
|
||||
def on_l2cap_connection(self, channel: l2cap.ClassicChannel) -> None:
|
||||
logger.debug(color('<<< stream channel connected', 'magenta'))
|
||||
self.rtp_channel = channel
|
||||
channel.on('open', self.on_l2cap_channel_open)
|
||||
channel.on('close', self.on_l2cap_channel_close)
|
||||
channel.on(channel.EVENT_OPEN, self.on_l2cap_channel_open)
|
||||
channel.on(channel.EVENT_CLOSE, self.on_l2cap_channel_close)
|
||||
|
||||
# We don't need more channels
|
||||
self.protocol.channel_acceptor = None
|
||||
|
||||
def on_l2cap_channel_open(self):
|
||||
def on_l2cap_channel_open(self) -> None:
|
||||
logger.debug(color('<<< stream channel open', 'magenta'))
|
||||
self.local_endpoint.on_rtp_channel_open()
|
||||
|
||||
def on_l2cap_channel_close(self):
|
||||
def on_l2cap_channel_close(self) -> None:
|
||||
logger.debug(color('<<< stream channel closed', 'magenta'))
|
||||
self.local_endpoint.on_rtp_channel_close()
|
||||
self.local_endpoint.in_use = 0
|
||||
@@ -2065,6 +2093,19 @@ class DiscoveredStreamEndPoint(StreamEndPoint, StreamEndPointProxy):
|
||||
class LocalStreamEndPoint(StreamEndPoint, utils.EventEmitter):
|
||||
stream: Optional[Stream]
|
||||
|
||||
EVENT_CONFIGURATION = "configuration"
|
||||
EVENT_OPEN = "open"
|
||||
EVENT_START = "start"
|
||||
EVENT_STOP = "stop"
|
||||
EVENT_RTP_PACKET = "rtp_packet"
|
||||
EVENT_SUSPEND = "suspend"
|
||||
EVENT_CLOSE = "close"
|
||||
EVENT_ABORT = "abort"
|
||||
EVENT_DELAY_REPORT = "delay_report"
|
||||
EVENT_SECURITY_CONTROL = "security_control"
|
||||
EVENT_RTP_CHANNEL_OPEN = "rtp_channel_open"
|
||||
EVENT_RTP_CHANNEL_CLOSE = "rtp_channel_close"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
protocol: Protocol,
|
||||
@@ -2080,52 +2121,65 @@ class LocalStreamEndPoint(StreamEndPoint, utils.EventEmitter):
|
||||
self.configuration = configuration if configuration is not None else []
|
||||
self.stream = None
|
||||
|
||||
async def start(self):
|
||||
pass
|
||||
async def start(self) -> None:
|
||||
"""[Source Only] Handles when receiving start command."""
|
||||
|
||||
async def stop(self):
|
||||
pass
|
||||
async def stop(self) -> None:
|
||||
"""[Source Only] Handles when receiving stop command."""
|
||||
|
||||
async def close(self):
|
||||
pass
|
||||
async def close(self) -> None:
|
||||
"""[Source Only] Handles when receiving close command."""
|
||||
|
||||
def on_reconfigure_command(self, command):
|
||||
pass
|
||||
def on_reconfigure_command(self, command) -> Optional[Message]:
|
||||
return None
|
||||
|
||||
def on_set_configuration_command(self, configuration):
|
||||
def on_set_configuration_command(self, configuration) -> Optional[Message]:
|
||||
logger.debug(
|
||||
'<<< received configuration: '
|
||||
f'{",".join([str(capability) for capability in configuration])}'
|
||||
)
|
||||
self.configuration = configuration
|
||||
self.emit('configuration')
|
||||
self.emit(self.EVENT_CONFIGURATION)
|
||||
return None
|
||||
|
||||
def on_get_configuration_command(self):
|
||||
def on_get_configuration_command(self) -> Optional[Message]:
|
||||
return Get_Configuration_Response(self.configuration)
|
||||
|
||||
def on_open_command(self):
|
||||
self.emit('open')
|
||||
def on_open_command(self) -> Optional[Message]:
|
||||
self.emit(self.EVENT_OPEN)
|
||||
return None
|
||||
|
||||
def on_start_command(self):
|
||||
self.emit('start')
|
||||
def on_start_command(self) -> Optional[Message]:
|
||||
self.emit(self.EVENT_START)
|
||||
return None
|
||||
|
||||
def on_suspend_command(self):
|
||||
self.emit('suspend')
|
||||
def on_suspend_command(self) -> Optional[Message]:
|
||||
self.emit(self.EVENT_SUSPEND)
|
||||
return None
|
||||
|
||||
def on_close_command(self):
|
||||
self.emit('close')
|
||||
def on_close_command(self) -> Optional[Message]:
|
||||
self.emit(self.EVENT_CLOSE)
|
||||
return None
|
||||
|
||||
def on_abort_command(self):
|
||||
self.emit('abort')
|
||||
def on_abort_command(self) -> Optional[Message]:
|
||||
self.emit(self.EVENT_ABORT)
|
||||
return None
|
||||
|
||||
def on_delayreport_command(self, delay: int):
|
||||
self.emit('delay_report', delay)
|
||||
def on_delayreport_command(self, delay: int) -> Optional[Message]:
|
||||
self.emit(self.EVENT_DELAY_REPORT, delay)
|
||||
return None
|
||||
|
||||
def on_rtp_channel_open(self):
|
||||
self.emit('rtp_channel_open')
|
||||
def on_security_control_command(self, data: bytes) -> Optional[Message]:
|
||||
self.emit(self.EVENT_SECURITY_CONTROL, data)
|
||||
return None
|
||||
|
||||
def on_rtp_channel_close(self):
|
||||
self.emit('rtp_channel_close')
|
||||
def on_rtp_channel_open(self) -> None:
|
||||
self.emit(self.EVENT_RTP_CHANNEL_OPEN)
|
||||
return None
|
||||
|
||||
def on_rtp_channel_close(self) -> None:
|
||||
self.emit(self.EVENT_RTP_CHANNEL_CLOSE)
|
||||
return None
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@@ -2156,13 +2210,13 @@ class LocalSource(LocalStreamEndPoint):
|
||||
if self.packet_pump and self.stream and self.stream.rtp_channel:
|
||||
return await self.packet_pump.start(self.stream.rtp_channel)
|
||||
|
||||
self.emit('start')
|
||||
self.emit(self.EVENT_START)
|
||||
|
||||
async def stop(self) -> None:
|
||||
if self.packet_pump:
|
||||
return await self.packet_pump.stop()
|
||||
|
||||
self.emit('stop')
|
||||
self.emit(self.EVENT_STOP)
|
||||
|
||||
def on_start_command(self):
|
||||
asyncio.create_task(self.start())
|
||||
@@ -2203,4 +2257,4 @@ class LocalSink(LocalStreamEndPoint):
|
||||
f'{color("<<< RTP Packet:", "green")} '
|
||||
f'{rtp_packet} {rtp_packet.payload[:16].hex()}'
|
||||
)
|
||||
self.emit('rtp_packet', rtp_packet)
|
||||
self.emit(self.EVENT_RTP_PACKET, rtp_packet)
|
||||
|
||||
Reference in New Issue
Block a user