diff --git a/apps/bench.py b/apps/bench.py index 4708403..8b37883 100644 --- a/apps/bench.py +++ b/apps/bench.py @@ -24,6 +24,7 @@ import time import click +from bumble import l2cap from bumble.core import ( BT_BR_EDR_TRANSPORT, BT_LE_TRANSPORT, @@ -85,6 +86,7 @@ DEFAULT_LINGER_TIME = 1.0 DEFAULT_RFCOMM_CHANNEL = 8 + # ----------------------------------------------------------------------------- # Utils # ----------------------------------------------------------------------------- @@ -197,6 +199,7 @@ class PacketType(enum.IntEnum): PACKET_FLAG_LAST = 1 + # ----------------------------------------------------------------------------- # Sender # ----------------------------------------------------------------------------- @@ -659,17 +662,19 @@ class L2capClient(StreamedPacketIO): self.mps = mps self.ready = asyncio.Event() - async def on_connection(self, connection): + async def on_connection(self, connection: Connection) -> None: connection.on('disconnection', self.on_disconnection) # Connect a new L2CAP channel print(color(f'>>> Opening L2CAP channel on PSM = {self.psm}', 'yellow')) try: - l2cap_channel = await connection.open_l2cap_channel( - psm=self.psm, - max_credits=self.max_credits, - mtu=self.mtu, - mps=self.mps, + l2cap_channel = await connection.create_l2cap_channel( + spec=l2cap.LeCreditBasedChannelSpec( + psm=self.psm, + max_credits=self.max_credits, + mtu=self.mtu, + mps=self.mps, + ) ) print(color('*** L2CAP channel:', 'cyan'), l2cap_channel) except Exception as error: @@ -695,7 +700,7 @@ class L2capClient(StreamedPacketIO): class L2capServer(StreamedPacketIO): def __init__( self, - device, + device: Device, psm=DEFAULT_L2CAP_PSM, max_credits=DEFAULT_L2CAP_MAX_CREDITS, mtu=DEFAULT_L2CAP_MTU, @@ -706,12 +711,11 @@ class L2capServer(StreamedPacketIO): self.ready = asyncio.Event() # Listen for incoming L2CAP CoC connections - device.register_l2cap_channel_server( - psm=psm, - server=self.on_l2cap_channel, - max_credits=max_credits, - mtu=mtu, - mps=mps, + device.create_l2cap_server( + spec=l2cap.LeCreditBasedChannelSpec( + psm=psm, mtu=mtu, mps=mps, max_credits=max_credits + ), + handler=self.on_l2cap_channel, ) print(color(f'### Listening for CoC connection on PSM {psm}', 'yellow')) diff --git a/apps/gg_bridge.py b/apps/gg_bridge.py index 88ebdc5..12d16e4 100644 --- a/apps/gg_bridge.py +++ b/apps/gg_bridge.py @@ -21,6 +21,7 @@ import struct import logging import click +from bumble import l2cap from bumble.colors import color from bumble.device import Device, Peer from bumble.core import AdvertisingData @@ -204,7 +205,7 @@ class GattlinkHubBridge(GattlinkL2capEndpoint, Device.Listener): # ----------------------------------------------------------------------------- class GattlinkNodeBridge(GattlinkL2capEndpoint, Device.Listener): - def __init__(self, device): + def __init__(self, device: Device): super().__init__() self.device = device self.peer = None @@ -218,7 +219,12 @@ class GattlinkNodeBridge(GattlinkL2capEndpoint, Device.Listener): # Listen for incoming L2CAP CoC connections psm = 0xFB - device.register_l2cap_channel_server(0xFB, self.on_coc) + device.create_l2cap_server( + spec=l2cap.LeCreditBasedChannelSpec( + psm=0xFB, + ), + handler=self.on_coc, + ) print(f'### Listening for CoC connection on PSM {psm}') # Setup the Gattlink service diff --git a/apps/l2cap_bridge.py b/apps/l2cap_bridge.py index 83379a0..14bd759 100644 --- a/apps/l2cap_bridge.py +++ b/apps/l2cap_bridge.py @@ -20,6 +20,7 @@ import logging import os import click +from bumble import l2cap from bumble.colors import color from bumble.transport import open_transport_or_link from bumble.device import Device @@ -47,14 +48,13 @@ class ServerBridge: self.tcp_host = tcp_host self.tcp_port = tcp_port - async def start(self, device): + async def start(self, device: Device) -> None: # Listen for incoming L2CAP CoC connections - device.register_l2cap_channel_server( - psm=self.psm, - server=self.on_coc, - max_credits=self.max_credits, - mtu=self.mtu, - mps=self.mps, + device.create_l2cap_server( + spec=l2cap.LeCreditBasedChannelSpec( + psm=self.psm, mtu=self.mtu, mps=self.mps, max_credits=self.max_credits + ), + handler=self.on_coc, ) print(color(f'### Listening for CoC connection on PSM {self.psm}', 'yellow')) @@ -195,11 +195,13 @@ class ClientBridge: # Connect a new L2CAP channel print(color(f'>>> Opening L2CAP channel on PSM = {self.psm}', 'yellow')) try: - l2cap_channel = await connection.open_l2cap_channel( - psm=self.psm, - max_credits=self.max_credits, - mtu=self.mtu, - mps=self.mps, + l2cap_channel = await connection.create_l2cap_channel( + spec=l2cap.LeCreditBasedChannelSpec( + psm=self.psm, + max_credits=self.max_credits, + mtu=self.mtu, + mps=self.mps, + ) ) print(color('*** L2CAP channel:', 'cyan'), l2cap_channel) except Exception as error: diff --git a/apps/speaker/speaker.py b/apps/speaker/speaker.py index e451c04..84e05a0 100644 --- a/apps/speaker/speaker.py +++ b/apps/speaker/speaker.py @@ -641,7 +641,7 @@ class Speaker: self.device.on('connection', self.on_bluetooth_connection) # Create a listener to wait for AVDTP connections - self.listener = Listener(Listener.create_registrar(self.device)) + self.listener = Listener.for_device(self.device) self.listener.on('connection', self.on_avdtp_connection) print(f'Speaker ready to play, codec={color(self.codec, "cyan")}') diff --git a/bumble/l2cap.py b/bumble/l2cap.py index 749f0d3..7a2f0ed 100644 --- a/bumble/l2cap.py +++ b/bumble/l2cap.py @@ -1036,9 +1036,11 @@ class LeCreditBasedChannel(EventEmitter): out_queue: Deque[bytes] connection_result: Optional[asyncio.Future[LeCreditBasedChannel]] disconnection_result: Optional[asyncio.Future[None]] + in_sdu: Optional[bytes] out_sdu: Optional[bytes] state: State connection: Connection + sink: Optional[Callable[[bytes], Any]] def __init__( self, @@ -1525,7 +1527,7 @@ class ChannelManager: if cid in self.fixed_channels: del self.fixed_channels[cid] - @deprecated("Please use create_classic_channel_server") + @deprecated("Please use create_classic_server") def register_server( self, psm: int, @@ -1540,7 +1542,7 @@ class ChannelManager: spec: ClassicChannelSpec, handler: Optional[Callable[[ClassicChannel], Any]] = None, ) -> ClassicChannelServer: - if spec.psm is None: + if not spec.psm: # Find a free PSM for candidate in range( L2CAP_PSM_DYNAMIC_RANGE_START, L2CAP_PSM_DYNAMIC_RANGE_END + 1, 2 @@ -1592,7 +1594,7 @@ class ChannelManager: spec: LeCreditBasedChannelSpec, handler: Optional[Callable[[LeCreditBasedChannel], Any]] = None, ) -> LeCreditBasedChannelServer: - if spec.psm is None: + if not spec.psm: # Find a free PSM for candidate in range( L2CAP_LE_PSM_DYNAMIC_RANGE_START, L2CAP_LE_PSM_DYNAMIC_RANGE_END + 1 diff --git a/bumble/profiles/asha_service.py b/bumble/profiles/asha_service.py index 6898397..412b28a 100644 --- a/bumble/profiles/asha_service.py +++ b/bumble/profiles/asha_service.py @@ -19,6 +19,8 @@ import struct import logging from typing import List + +from bumble import l2cap from ..core import AdvertisingData from ..device import Device, Connection from ..gatt import ( @@ -149,7 +151,10 @@ class AshaService(TemplateService): channel.sink = on_data # let the server find a free PSM - self.psm = self.device.register_l2cap_channel_server(self.psm, on_coc, 8) + self.psm = device.create_l2cap_server( + spec=l2cap.LeCreditBasedChannelSpec(psm=self.psm, max_credits=8), + handler=on_coc, + ).psm self.le_psm_out_characteristic = Characteristic( GATT_ASHA_LE_PSM_OUT_CHARACTERISTIC, Characteristic.Properties.READ, diff --git a/bumble/rfcomm.py b/bumble/rfcomm.py index 4002dc7..53e98e0 100644 --- a/bumble/rfcomm.py +++ b/bumble/rfcomm.py @@ -898,8 +898,8 @@ class Client: async def start(self) -> Multiplexer: # Create a new L2CAP connection try: - self.l2cap_channel = await self.device.l2cap_channel_manager.connect( - self.connection, RFCOMM_PSM + self.l2cap_channel = await self.connection.create_l2cap_channel( + spec=l2cap.ClassicChannelSpec(RFCOMM_PSM) ) except ProtocolError as error: logger.warning(f'L2CAP connection failed: {error}') @@ -936,7 +936,9 @@ class Server(EventEmitter): self.acceptors = {} # Register ourselves with the L2CAP channel manager - device.register_l2cap_server(RFCOMM_PSM, self.on_connection) + device.create_l2cap_server( + spec=l2cap.ClassicChannelSpec(psm=RFCOMM_PSM), handler=self.on_connection + ) def listen(self, acceptor: Callable[[DLC], None], channel: int = 0) -> int: if channel: diff --git a/bumble/sdp.py b/bumble/sdp.py index 01e72da..ae01301 100644 --- a/bumble/sdp.py +++ b/bumble/sdp.py @@ -766,8 +766,9 @@ class Client: self.channel = None async def connect(self, connection: Connection) -> None: - result = await self.device.l2cap_channel_manager.connect(connection, SDP_PSM) - self.channel = result + self.channel = await connection.create_l2cap_channel( + spec=l2cap.ClassicChannelSpec(SDP_PSM) + ) async def disconnect(self) -> None: if self.channel: @@ -933,7 +934,9 @@ class Server: self.current_response = None def register(self, l2cap_channel_manager: l2cap.ChannelManager) -> None: - l2cap_channel_manager.register_server(SDP_PSM, self.on_connection) + l2cap_channel_manager.create_classic_server( + spec=l2cap.ClassicChannelSpec(psm=SDP_PSM), handler=self.on_connection + ) def send_response(self, response): logger.debug(f'{color(">>> Sending SDP Response", "blue")}: {response}') diff --git a/examples/run_a2dp_sink.py b/examples/run_a2dp_sink.py index b20f0d6..61bdce3 100644 --- a/examples/run_a2dp_sink.py +++ b/examples/run_a2dp_sink.py @@ -131,7 +131,7 @@ async def main(): await device.power_on() # Create a listener to wait for AVDTP connections - listener = Listener(Listener.create_registrar(device)) + listener = Listener.for_device(device) listener.on('connection', on_avdtp_connection) if len(sys.argv) >= 5: diff --git a/examples/run_a2dp_source.py b/examples/run_a2dp_source.py index 2443518..69dc2d0 100644 --- a/examples/run_a2dp_source.py +++ b/examples/run_a2dp_source.py @@ -179,7 +179,7 @@ async def main(): await stream_packets(read, protocol) else: # Create a listener to wait for AVDTP connections - listener = Listener(Listener.create_registrar(device), version=(1, 2)) + listener = Listener.for_device(device=device, version=(1, 2)) listener.on( 'connection', lambda protocol: on_avdtp_connection(read, protocol) ) diff --git a/examples/run_asha_sink.py b/examples/run_asha_sink.py index 3e4955d..2d6f0d5 100644 --- a/examples/run_asha_sink.py +++ b/examples/run_asha_sink.py @@ -21,6 +21,7 @@ import sys import os import logging +from bumble import l2cap from bumble.core import AdvertisingData from bumble.device import Device from bumble.transport import open_transport_or_link @@ -95,8 +96,10 @@ async def main(): channel.sink = on_data - psm = device.register_l2cap_channel_server(0, on_coc, 8) - print(f'### LE_PSM_OUT = {psm}') + server = device.create_l2cap_server( + spec=l2cap.LeCreditBasedChannelSpec(max_credits=8), handler=on_coc + ) + print(f'### LE_PSM_OUT = {server.psm}') # Add the ASHA service to the GATT server read_only_properties_characteristic = Characteristic( @@ -147,7 +150,7 @@ async def main(): ASHA_LE_PSM_OUT_CHARACTERISTIC, Characteristic.Properties.READ, Characteristic.READABLE, - struct.pack('