mirror of
https://github.com/google/bumble.git
synced 2026-05-08 03:58:01 +00:00
ASCS: Handle when CIS link is established before enable
This commit is contained in:
@@ -452,6 +452,16 @@ class AseStateMachine(gatt.Characteristic):
|
|||||||
|
|
||||||
self.metadata = le_audio.Metadata.from_bytes(metadata)
|
self.metadata = le_audio.Metadata.from_bytes(metadata)
|
||||||
self.state = self.State.ENABLING
|
self.state = self.State.ENABLING
|
||||||
|
# CIS could be established before enable.
|
||||||
|
if cis_link := next(
|
||||||
|
(
|
||||||
|
cis_link
|
||||||
|
for cis_link in self.service.device.cis_links.values()
|
||||||
|
if cis_link.cig_id == self.cig_id and cis_link.cis_id == self.cis_id
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
):
|
||||||
|
self.on_cis_establishment(cis_link)
|
||||||
|
|
||||||
return (AseResponseCode.SUCCESS, AseReasonCode.NONE)
|
return (AseResponseCode.SUCCESS, AseReasonCode.NONE)
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
# Imports
|
# Imports
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
import asyncio
|
import asyncio
|
||||||
import os
|
|
||||||
import functools
|
import functools
|
||||||
import pytest
|
import pytest
|
||||||
import logging
|
import logging
|
||||||
@@ -55,7 +54,7 @@ from bumble.profiles.pacs import (
|
|||||||
PublishedAudioCapabilitiesServiceProxy,
|
PublishedAudioCapabilitiesServiceProxy,
|
||||||
)
|
)
|
||||||
from bumble.profiles.le_audio import Metadata
|
from bumble.profiles.le_audio import Metadata
|
||||||
from tests.test_utils import TwoDevices
|
from tests.test_utils import TwoDevices, async_barrier
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
@@ -441,15 +440,114 @@ async def test_ascs():
|
|||||||
assert (await notifications[1].get())[:2] == bytes([1, AseStateMachine.State.IDLE])
|
assert (await notifications[1].get())[:2] == bytes([1, AseStateMachine.State.IDLE])
|
||||||
assert (await notifications[2].get())[:2] == bytes([2, AseStateMachine.State.IDLE])
|
assert (await notifications[2].get())[:2] == bytes([2, AseStateMachine.State.IDLE])
|
||||||
|
|
||||||
await asyncio.sleep(0.001)
|
await async_barrier()
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
async def run():
|
@pytest.mark.asyncio
|
||||||
await test_pacs()
|
async def test_ascs_enable_source_then_sink():
|
||||||
|
devices = TwoDevices()
|
||||||
|
ascs_server = AudioStreamControlService(
|
||||||
|
device=devices[1], sink_ase_id=[1], source_ase_id=[2]
|
||||||
|
)
|
||||||
|
sink_ase = ascs_server.ase_state_machines[1]
|
||||||
|
source_ase = ascs_server.ase_state_machines[2]
|
||||||
|
devices[1].add_service(ascs_server)
|
||||||
|
condition = asyncio.Condition()
|
||||||
|
|
||||||
|
async def on_state_change():
|
||||||
|
async with condition:
|
||||||
|
condition.notify_all()
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
sink_ase.on(sink_ase.EVENT_STATE_CHANGE, on_state_change)
|
||||||
if __name__ == '__main__':
|
source_ase.on(sink_ase.EVENT_STATE_CHANGE, on_state_change)
|
||||||
logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())
|
|
||||||
asyncio.run(run())
|
await devices.setup_connection()
|
||||||
|
peer = device.Peer(devices.connections[0])
|
||||||
|
ascs_client = await peer.discover_service_and_create_proxy(
|
||||||
|
AudioStreamControlServiceProxy
|
||||||
|
)
|
||||||
|
|
||||||
|
# Config Codec
|
||||||
|
config = CodecSpecificConfiguration(
|
||||||
|
sampling_frequency=SamplingFrequency.FREQ_48000,
|
||||||
|
frame_duration=FrameDuration.DURATION_10000_US,
|
||||||
|
audio_channel_allocation=AudioLocation.FRONT_LEFT,
|
||||||
|
octets_per_codec_frame=120,
|
||||||
|
codec_frames_per_sdu=1,
|
||||||
|
)
|
||||||
|
await ascs_client.ase_control_point.write_value(
|
||||||
|
ASE_Config_Codec(
|
||||||
|
ase_id=[1, 2],
|
||||||
|
target_latency=[3, 4],
|
||||||
|
target_phy=[5, 6],
|
||||||
|
codec_id=[CodingFormat(CodecID.LC3), CodingFormat(CodecID.LC3)],
|
||||||
|
codec_specific_configuration=[config, config],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
async with condition:
|
||||||
|
await condition.wait_for(
|
||||||
|
lambda: (
|
||||||
|
sink_ase.state == AseStateMachine.State.CODEC_CONFIGURED
|
||||||
|
and source_ase.state == AseStateMachine.State.CODEC_CONFIGURED
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Config QOS
|
||||||
|
await ascs_client.ase_control_point.write_value(
|
||||||
|
ASE_Config_QOS(
|
||||||
|
ase_id=[1, 2],
|
||||||
|
cig_id=[1, 1],
|
||||||
|
cis_id=[1, 1],
|
||||||
|
sdu_interval=[100, 100],
|
||||||
|
framing=[0, 0],
|
||||||
|
phy=[1, 1],
|
||||||
|
max_sdu=[100, 100],
|
||||||
|
retransmission_number=[16, 16],
|
||||||
|
max_transport_latency=[150, 150],
|
||||||
|
presentation_delay=[10, 10],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
async with condition:
|
||||||
|
await condition.wait_for(
|
||||||
|
lambda: (
|
||||||
|
sink_ase.state == AseStateMachine.State.QOS_CONFIGURED
|
||||||
|
and source_ase.state == AseStateMachine.State.QOS_CONFIGURED
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Enable ASE 2
|
||||||
|
await ascs_client.ase_control_point.write_value(
|
||||||
|
ASE_Enable(ase_id=[2], metadata=[b'foo'])
|
||||||
|
)
|
||||||
|
await async_barrier()
|
||||||
|
cis_handles = await devices[0].setup_cig(
|
||||||
|
device.CigParameters(
|
||||||
|
cig_id=1,
|
||||||
|
cis_parameters=[device.CigParameters.CisParameters(cis_id=1)],
|
||||||
|
sdu_interval_c_to_p=100,
|
||||||
|
sdu_interval_p_to_c=100,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
await devices[0].create_cis([(cis_handles[0], devices.connections[0])])
|
||||||
|
|
||||||
|
async with condition:
|
||||||
|
await condition.wait_for(
|
||||||
|
lambda: (source_ase.state == AseStateMachine.State.ENABLING)
|
||||||
|
)
|
||||||
|
await ascs_client.ase_control_point.write_value(
|
||||||
|
ASE_Receiver_Start_Ready(ase_id=[2])
|
||||||
|
)
|
||||||
|
async with condition:
|
||||||
|
await condition.wait_for(
|
||||||
|
lambda: (source_ase.state == AseStateMachine.State.STREAMING)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Enable ASE 1
|
||||||
|
await ascs_client.ase_control_point.write_value(
|
||||||
|
ASE_Enable(ase_id=[1], metadata=[b'bar'])
|
||||||
|
)
|
||||||
|
async with condition:
|
||||||
|
await condition.wait_for(
|
||||||
|
lambda: (sink_ase.state == AseStateMachine.State.STREAMING)
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user