forked from auracaster/bumble_mirror
fix after rebase merge
This commit is contained in:
@@ -495,6 +495,10 @@ async def run_assist(
|
|||||||
print(color('Scanning for any broadcast', 'cyan'))
|
print(color('Scanning for any broadcast', 'cyan'))
|
||||||
broadcast = await find_broadcast_by_name(device, broadcast_name)
|
broadcast = await find_broadcast_by_name(device, broadcast_name)
|
||||||
|
|
||||||
|
if broadcast.broadcast_audio_announcement is None:
|
||||||
|
print(color('No broadcast audio announcement found', 'red'))
|
||||||
|
return
|
||||||
|
|
||||||
if (
|
if (
|
||||||
broadcast.basic_audio_announcement is None
|
broadcast.basic_audio_announcement is None
|
||||||
or not broadcast.basic_audio_announcement.subgroups
|
or not broadcast.basic_audio_announcement.subgroups
|
||||||
|
|||||||
@@ -484,7 +484,7 @@ class Speaker:
|
|||||||
)
|
)
|
||||||
) + bytes(bap.UnicastServerAdvertisingData())
|
) + bytes(bap.UnicastServerAdvertisingData())
|
||||||
|
|
||||||
def on_pdu(pdu: HCI_IsoDataPacket, ase: bap.AseStateMachine):
|
def on_pdu(pdu: HCI_IsoDataPacket, ase: ascs.AseStateMachine):
|
||||||
codec_config = ase.codec_specific_configuration
|
codec_config = ase.codec_specific_configuration
|
||||||
assert isinstance(codec_config, bap.CodecSpecificConfiguration)
|
assert isinstance(codec_config, bap.CodecSpecificConfiguration)
|
||||||
pcm = decode(
|
pcm = decode(
|
||||||
@@ -494,7 +494,7 @@ class Speaker:
|
|||||||
)
|
)
|
||||||
self.device.abort_on('disconnection', self.ui_server.send_audio(pcm))
|
self.device.abort_on('disconnection', self.ui_server.send_audio(pcm))
|
||||||
|
|
||||||
def on_ase_state_change(ase: bap.AseStateMachine) -> None:
|
def on_ase_state_change(ase: ascs.AseStateMachine) -> None:
|
||||||
if ase.state == ascs.AseStateMachine.State.STREAMING:
|
if ase.state == ascs.AseStateMachine.State.STREAMING:
|
||||||
codec_config = ase.codec_specific_configuration
|
codec_config = ase.codec_specific_configuration
|
||||||
assert isinstance(codec_config, bap.CodecSpecificConfiguration)
|
assert isinstance(codec_config, bap.CodecSpecificConfiguration)
|
||||||
|
|||||||
@@ -988,7 +988,8 @@ class PeriodicAdvertisingSync(EventEmitter):
|
|||||||
self.device.periodic_advertising_syncs.remove(self)
|
self.device.periodic_advertising_syncs.remove(self)
|
||||||
|
|
||||||
async def transfer(self, connection: Connection, service_data: int = 0) -> None:
|
async def transfer(self, connection: Connection, service_data: int = 0) -> None:
|
||||||
await connection.transfer_periodic_sync(self.sync_handle, service_data)
|
if self.sync_handle is not None:
|
||||||
|
await connection.transfer_periodic_sync(self.sync_handle, service_data)
|
||||||
|
|
||||||
def on_establishment(
|
def on_establishment(
|
||||||
self,
|
self,
|
||||||
@@ -3606,7 +3607,8 @@ class Device(CompositeEventEmitter):
|
|||||||
connection_handle=connection.handle,
|
connection_handle=connection.handle,
|
||||||
service_data=service_data,
|
service_data=service_data,
|
||||||
sync_handle=sync_handle,
|
sync_handle=sync_handle,
|
||||||
), check_result=True
|
),
|
||||||
|
check_result=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def find_peer_by_name(self, name, transport=BT_LE_TRANSPORT):
|
async def find_peer_by_name(self, name, transport=BT_LE_TRANSPORT):
|
||||||
@@ -3837,6 +3839,7 @@ class Device(CompositeEventEmitter):
|
|||||||
if self.keystore is None:
|
if self.keystore is None:
|
||||||
raise InvalidOperationError('no key store')
|
raise InvalidOperationError('no key store')
|
||||||
|
|
||||||
|
logger.debug(f'Looking up key for {connection.peer_address}')
|
||||||
keys = await self.keystore.get(str(connection.peer_address))
|
keys = await self.keystore.get(str(connection.peer_address))
|
||||||
if keys is None:
|
if keys is None:
|
||||||
raise InvalidOperationError('keys not found in key store')
|
raise InvalidOperationError('keys not found in key store')
|
||||||
@@ -4315,6 +4318,12 @@ class Device(CompositeEventEmitter):
|
|||||||
role: int,
|
role: int,
|
||||||
connection_parameters: ConnectionParameters,
|
connection_parameters: ConnectionParameters,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
# Convert all-zeros addresses into None.
|
||||||
|
if self_resolvable_address == Address.ANY_RANDOM:
|
||||||
|
self_resolvable_address = None
|
||||||
|
if peer_resolvable_address == Address.ANY_RANDOM:
|
||||||
|
peer_resolvable_address = None
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f'*** Connection: [0x{connection_handle:04X}] '
|
f'*** Connection: [0x{connection_handle:04X}] '
|
||||||
f'{peer_address} {"" if role is None else HCI_Constant.role_name(role)}'
|
f'{peer_address} {"" if role is None else HCI_Constant.role_name(role)}'
|
||||||
@@ -4374,12 +4383,6 @@ class Device(CompositeEventEmitter):
|
|||||||
else self.random_address
|
else self.random_address
|
||||||
)
|
)
|
||||||
|
|
||||||
# Convert all-zeros addresses into None.
|
|
||||||
if self_resolvable_address == Address.ANY_RANDOM:
|
|
||||||
self_resolvable_address = None
|
|
||||||
if peer_resolvable_address == Address.ANY_RANDOM:
|
|
||||||
peer_resolvable_address = None
|
|
||||||
|
|
||||||
# Create a connection.
|
# Create a connection.
|
||||||
connection = Connection(
|
connection = Connection(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ from typing import Any, Dict, List, Optional, Sequence, Tuple, Type, Union
|
|||||||
|
|
||||||
from bumble import colors
|
from bumble import colors
|
||||||
from bumble.profiles.bap import CodecSpecificConfiguration
|
from bumble.profiles.bap import CodecSpecificConfiguration
|
||||||
|
from bumble.profiles import le_audio
|
||||||
from bumble import device
|
from bumble import device
|
||||||
from bumble import gatt
|
from bumble import gatt
|
||||||
from bumble import gatt_client
|
from bumble import gatt_client
|
||||||
@@ -299,8 +300,7 @@ class AseStateMachine(gatt.Characteristic):
|
|||||||
presentation_delay = 0
|
presentation_delay = 0
|
||||||
|
|
||||||
# Additional parameters in ENABLING, STREAMING, DISABLING State
|
# Additional parameters in ENABLING, STREAMING, DISABLING State
|
||||||
# TODO: Parse this
|
metadata = le_audio.Metadata()
|
||||||
metadata = b''
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -447,7 +447,7 @@ class AseStateMachine(gatt.Characteristic):
|
|||||||
AseReasonCode.NONE,
|
AseReasonCode.NONE,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.metadata = metadata
|
self.metadata = le_audio.Metadata.from_bytes(metadata)
|
||||||
self.state = self.State.ENABLING
|
self.state = self.State.ENABLING
|
||||||
|
|
||||||
return (AseResponseCode.SUCCESS, AseReasonCode.NONE)
|
return (AseResponseCode.SUCCESS, AseReasonCode.NONE)
|
||||||
@@ -499,7 +499,7 @@ class AseStateMachine(gatt.Characteristic):
|
|||||||
AseResponseCode.INVALID_ASE_STATE_MACHINE_TRANSITION,
|
AseResponseCode.INVALID_ASE_STATE_MACHINE_TRANSITION,
|
||||||
AseReasonCode.NONE,
|
AseReasonCode.NONE,
|
||||||
)
|
)
|
||||||
self.metadata = metadata
|
self.metadata = le_audio.Metadata.from_bytes(metadata)
|
||||||
return (AseResponseCode.SUCCESS, AseReasonCode.NONE)
|
return (AseResponseCode.SUCCESS, AseReasonCode.NONE)
|
||||||
|
|
||||||
def on_release(self) -> Tuple[AseResponseCode, AseReasonCode]:
|
def on_release(self) -> Tuple[AseResponseCode, AseReasonCode]:
|
||||||
@@ -576,8 +576,9 @@ class AseStateMachine(gatt.Characteristic):
|
|||||||
self.State.STREAMING,
|
self.State.STREAMING,
|
||||||
self.State.DISABLING,
|
self.State.DISABLING,
|
||||||
):
|
):
|
||||||
|
metadata_bytes = bytes(self.metadata)
|
||||||
additional_parameters = (
|
additional_parameters = (
|
||||||
bytes([self.cig_id, self.cis_id, len(self.metadata)]) + self.metadata
|
bytes([self.cig_id, self.cis_id, len(metadata_bytes)]) + metadata_bytes
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
additional_parameters = b''
|
additional_parameters = b''
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import struct
|
|||||||
from typing import Optional, Sequence, Union
|
from typing import Optional, Sequence, Union
|
||||||
|
|
||||||
from bumble.profiles.bap import AudioLocation, CodecSpecificCapabilities, ContextType
|
from bumble.profiles.bap import AudioLocation, CodecSpecificCapabilities, ContextType
|
||||||
|
from bumble.profiles import le_audio
|
||||||
from bumble import gatt
|
from bumble import gatt
|
||||||
from bumble import gatt_client
|
from bumble import gatt_client
|
||||||
from bumble import hci
|
from bumble import hci
|
||||||
@@ -37,10 +38,11 @@ logger = logging.getLogger(__name__)
|
|||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
class PacRecord:
|
class PacRecord:
|
||||||
|
'''Published Audio Capabilities Service, Table 3.2/3.4.'''
|
||||||
|
|
||||||
coding_format: hci.CodingFormat
|
coding_format: hci.CodingFormat
|
||||||
codec_specific_capabilities: Union[CodecSpecificCapabilities, bytes]
|
codec_specific_capabilities: Union[CodecSpecificCapabilities, bytes]
|
||||||
# TODO: Parse Metadata
|
metadata: le_audio.Metadata = dataclasses.field(default_factory=le_audio.Metadata)
|
||||||
metadata: bytes = b''
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_bytes(cls, data: bytes) -> PacRecord:
|
def from_bytes(cls, data: bytes) -> PacRecord:
|
||||||
@@ -53,7 +55,8 @@ class PacRecord:
|
|||||||
]
|
]
|
||||||
offset += codec_specific_capabilities_size
|
offset += codec_specific_capabilities_size
|
||||||
metadata_size = data[offset]
|
metadata_size = data[offset]
|
||||||
metadata = data[offset : offset + metadata_size]
|
offset += 1
|
||||||
|
metadata = le_audio.Metadata.from_bytes(data[offset : offset + metadata_size])
|
||||||
|
|
||||||
codec_specific_capabilities: Union[CodecSpecificCapabilities, bytes]
|
codec_specific_capabilities: Union[CodecSpecificCapabilities, bytes]
|
||||||
if coding_format.codec_id == hci.CodecID.VENDOR_SPECIFIC:
|
if coding_format.codec_id == hci.CodecID.VENDOR_SPECIFIC:
|
||||||
@@ -71,12 +74,13 @@ class PacRecord:
|
|||||||
|
|
||||||
def __bytes__(self) -> bytes:
|
def __bytes__(self) -> bytes:
|
||||||
capabilities_bytes = bytes(self.codec_specific_capabilities)
|
capabilities_bytes = bytes(self.codec_specific_capabilities)
|
||||||
|
metadata_bytes = bytes(self.metadata)
|
||||||
return (
|
return (
|
||||||
bytes(self.coding_format)
|
bytes(self.coding_format)
|
||||||
+ bytes([len(capabilities_bytes)])
|
+ bytes([len(capabilities_bytes)])
|
||||||
+ capabilities_bytes
|
+ capabilities_bytes
|
||||||
+ bytes([len(self.metadata)])
|
+ bytes([len(metadata_bytes)])
|
||||||
+ self.metadata
|
+ metadata_bytes
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -35,15 +35,13 @@ from bumble.hci import (
|
|||||||
CodingFormat,
|
CodingFormat,
|
||||||
OwnAddressType,
|
OwnAddressType,
|
||||||
)
|
)
|
||||||
|
from bumble.profiles.ascs import AudioStreamControlService
|
||||||
from bumble.profiles.bap import (
|
from bumble.profiles.bap import (
|
||||||
CodecSpecificCapabilities,
|
CodecSpecificCapabilities,
|
||||||
ContextType,
|
ContextType,
|
||||||
AudioLocation,
|
AudioLocation,
|
||||||
SupportedSamplingFrequency,
|
SupportedSamplingFrequency,
|
||||||
SupportedFrameDuration,
|
SupportedFrameDuration,
|
||||||
PacRecord,
|
|
||||||
PublishedAudioCapabilitiesService,
|
|
||||||
AudioStreamControlService,
|
|
||||||
UnicastServerAdvertisingData,
|
UnicastServerAdvertisingData,
|
||||||
)
|
)
|
||||||
from bumble.profiles.mcp import (
|
from bumble.profiles.mcp import (
|
||||||
@@ -52,7 +50,7 @@ from bumble.profiles.mcp import (
|
|||||||
MediaState,
|
MediaState,
|
||||||
MediaControlPointOpcode,
|
MediaControlPointOpcode,
|
||||||
)
|
)
|
||||||
|
from bumble.profiles.pacs import PacRecord, PublishedAudioCapabilitiesService
|
||||||
from bumble.transport import open_transport_or_link
|
from bumble.transport import open_transport_or_link
|
||||||
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ from bumble.hci import (
|
|||||||
CodingFormat,
|
CodingFormat,
|
||||||
HCI_IsoDataPacket,
|
HCI_IsoDataPacket,
|
||||||
)
|
)
|
||||||
|
from bumble.profiles.ascs import AseStateMachine, AudioStreamControlService
|
||||||
from bumble.profiles.bap import (
|
from bumble.profiles.bap import (
|
||||||
AseStateMachine,
|
|
||||||
UnicastServerAdvertisingData,
|
UnicastServerAdvertisingData,
|
||||||
CodecSpecificConfiguration,
|
CodecSpecificConfiguration,
|
||||||
CodecSpecificCapabilities,
|
CodecSpecificCapabilities,
|
||||||
@@ -43,13 +43,10 @@ from bumble.profiles.bap import (
|
|||||||
AudioLocation,
|
AudioLocation,
|
||||||
SupportedSamplingFrequency,
|
SupportedSamplingFrequency,
|
||||||
SupportedFrameDuration,
|
SupportedFrameDuration,
|
||||||
PacRecord,
|
|
||||||
PublishedAudioCapabilitiesService,
|
|
||||||
AudioStreamControlService,
|
|
||||||
)
|
)
|
||||||
from bumble.profiles.cap import CommonAudioServiceService
|
from bumble.profiles.cap import CommonAudioServiceService
|
||||||
from bumble.profiles.csip import CoordinatedSetIdentificationService, SirkType
|
from bumble.profiles.csip import CoordinatedSetIdentificationService, SirkType
|
||||||
|
from bumble.profiles.pacs import PacRecord, PublishedAudioCapabilitiesService
|
||||||
from bumble.transport import open_transport_or_link
|
from bumble.transport import open_transport_or_link
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ from bumble.hci import (
|
|||||||
CodingFormat,
|
CodingFormat,
|
||||||
OwnAddressType,
|
OwnAddressType,
|
||||||
)
|
)
|
||||||
|
from bumble.profiles.ascs import AudioStreamControlService
|
||||||
from bumble.profiles.bap import (
|
from bumble.profiles.bap import (
|
||||||
UnicastServerAdvertisingData,
|
UnicastServerAdvertisingData,
|
||||||
CodecSpecificCapabilities,
|
CodecSpecificCapabilities,
|
||||||
@@ -37,10 +38,8 @@ from bumble.profiles.bap import (
|
|||||||
AudioLocation,
|
AudioLocation,
|
||||||
SupportedSamplingFrequency,
|
SupportedSamplingFrequency,
|
||||||
SupportedFrameDuration,
|
SupportedFrameDuration,
|
||||||
PacRecord,
|
|
||||||
PublishedAudioCapabilitiesService,
|
|
||||||
AudioStreamControlService,
|
|
||||||
)
|
)
|
||||||
|
from bumble.profiles.pacs import PacRecord, PublishedAudioCapabilitiesService
|
||||||
from bumble.profiles.cap import CommonAudioServiceService
|
from bumble.profiles.cap import CommonAudioServiceService
|
||||||
from bumble.profiles.csip import CoordinatedSetIdentificationService, SirkType
|
from bumble.profiles.csip import CoordinatedSetIdentificationService, SirkType
|
||||||
from bumble.profiles.vcp import VolumeControlService
|
from bumble.profiles.vcp import VolumeControlService
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ def test_operations() -> None:
|
|||||||
def basic_broadcast_receive_state_check(brs: bass.BroadcastReceiveState) -> None:
|
def basic_broadcast_receive_state_check(brs: bass.BroadcastReceiveState) -> None:
|
||||||
serialized = bytes(brs)
|
serialized = bytes(brs)
|
||||||
parsed = bass.BroadcastReceiveState.from_bytes(serialized)
|
parsed = bass.BroadcastReceiveState.from_bytes(serialized)
|
||||||
|
assert parsed is not None
|
||||||
assert bytes(parsed) == serialized
|
assert bytes(parsed) == serialized
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user