quali #13
@@ -7,24 +7,19 @@ class AuracastQoSConfig(BaseModel):
|
|||||||
number_of_retransmissions: int
|
number_of_retransmissions: int
|
||||||
max_transport_latency_ms: int
|
max_transport_latency_ms: int
|
||||||
|
|
||||||
class AuracastQosHigh(AuracastQoSConfig):
|
class AuracastQosDefault(AuracastQoSConfig):
|
||||||
iso_int_multiple_10ms: int = 1
|
iso_int_multiple_10ms: int = 1
|
||||||
number_of_retransmissions:int = 4 #4
|
number_of_retransmissions:int = 4 #4
|
||||||
max_transport_latency_ms:int = 43 #varies from the default value in bumble (was 65)
|
max_transport_latency_ms:int = 43 #varies from the default value in bumble (was 65)
|
||||||
|
|
||||||
class AuracastQosMid(AuracastQoSConfig):
|
class AuracastQosFast(AuracastQoSConfig):
|
||||||
iso_int_multiple_10ms: int = 2
|
iso_int_multiple_10ms: int = 1
|
||||||
number_of_retransmissions:int = 3
|
number_of_retransmissions:int = 2
|
||||||
max_transport_latency_ms:int = 65
|
max_transport_latency_ms:int = 22
|
||||||
|
|
||||||
class AuracastQosLow(AuracastQoSConfig):
|
|
||||||
iso_int_multiple_10ms: int = 3
|
|
||||||
number_of_retransmissions:int = 2 #4
|
|
||||||
max_transport_latency_ms:int = 65 #varies from the default value in bumble (was 65)
|
|
||||||
|
|
||||||
|
|
||||||
class AuracastGlobalConfig(BaseModel):
|
class AuracastGlobalConfig(BaseModel):
|
||||||
qos_config: AuracastQoSConfig = AuracastQosHigh()
|
qos_config: AuracastQoSConfig = AuracastQosDefault()
|
||||||
debug: bool = False
|
debug: bool = False
|
||||||
device_name: str = 'Auracaster'
|
device_name: str = 'Auracaster'
|
||||||
transport: str = ''
|
transport: str = ''
|
||||||
@@ -59,6 +54,7 @@ class AuracastBigConfig(BaseModel):
|
|||||||
loop: bool = True
|
loop: bool = True
|
||||||
precode_wav: bool = False
|
precode_wav: bool = False
|
||||||
iso_que_len: int = 64
|
iso_que_len: int = 64
|
||||||
|
num_bis: int = 1 # 1 = mono (FRONT_LEFT), 2 = stereo (FRONT_LEFT + FRONT_RIGHT)
|
||||||
|
|
||||||
class AuracastBigConfigDeu(AuracastBigConfig):
|
class AuracastBigConfigDeu(AuracastBigConfig):
|
||||||
id: int = 12
|
id: int = 12
|
||||||
@@ -73,7 +69,7 @@ class AuracastBigConfigEng(AuracastBigConfig):
|
|||||||
random_address: str = 'F2:F1:F2:F3:F4:F5'
|
random_address: str = 'F2:F1:F2:F3:F4:F5'
|
||||||
name: str = 'Lecture Hall A'
|
name: str = 'Lecture Hall A'
|
||||||
language: str ='eng'
|
language: str ='eng'
|
||||||
program_info: str = 'Lecture EN'
|
program_info: str = 'Lecture EN'
|
||||||
audio_source: str = 'file:./testdata/wave_particle_5min_en.wav'
|
audio_source: str = 'file:./testdata/wave_particle_5min_en.wav'
|
||||||
|
|
||||||
class AuracastBigConfigFra(AuracastBigConfig):
|
class AuracastBigConfigFra(AuracastBigConfig):
|
||||||
@@ -82,7 +78,7 @@ class AuracastBigConfigFra(AuracastBigConfig):
|
|||||||
# French
|
# French
|
||||||
name: str = 'Auditoire A'
|
name: str = 'Auditoire A'
|
||||||
language: str ='fra'
|
language: str ='fra'
|
||||||
program_info: str = 'Auditoire FR'
|
program_info: str = 'Auditoire FR'
|
||||||
audio_source: str = 'file:./testdata/wave_particle_5min_fr.wav'
|
audio_source: str = 'file:./testdata/wave_particle_5min_fr.wav'
|
||||||
|
|
||||||
class AuracastBigConfigSpa(AuracastBigConfig):
|
class AuracastBigConfigSpa(AuracastBigConfig):
|
||||||
@@ -90,7 +86,7 @@ class AuracastBigConfigSpa(AuracastBigConfig):
|
|||||||
random_address: str = 'F4:F1:F2:F3:F4:F5'
|
random_address: str = 'F4:F1:F2:F3:F4:F5'
|
||||||
name: str = 'Auditorio A'
|
name: str = 'Auditorio A'
|
||||||
language: str ='spa'
|
language: str ='spa'
|
||||||
program_info: str = 'Auditorio ES'
|
program_info: str = 'Auditorio ES'
|
||||||
audio_source: str = 'file:./testdata/wave_particle_5min_es.wav'
|
audio_source: str = 'file:./testdata/wave_particle_5min_es.wav'
|
||||||
|
|
||||||
class AuracastBigConfigIta(AuracastBigConfig):
|
class AuracastBigConfigIta(AuracastBigConfig):
|
||||||
@@ -98,7 +94,7 @@ class AuracastBigConfigIta(AuracastBigConfig):
|
|||||||
random_address: str = 'F5:F1:F2:F3:F4:F5'
|
random_address: str = 'F5:F1:F2:F3:F4:F5'
|
||||||
name: str = 'Aula A'
|
name: str = 'Aula A'
|
||||||
language: str ='ita'
|
language: str ='ita'
|
||||||
program_info: str = 'Aula IT'
|
program_info: str = 'Aula IT'
|
||||||
audio_source: str = 'file:./testdata/wave_particle_5min_it.wav'
|
audio_source: str = 'file:./testdata/wave_particle_5min_it.wav'
|
||||||
|
|
||||||
|
|
||||||
@@ -107,7 +103,7 @@ class AuracastBigConfigPol(AuracastBigConfig):
|
|||||||
random_address: str = 'F6:F1:F2:F3:F4:F5'
|
random_address: str = 'F6:F1:F2:F3:F4:F5'
|
||||||
name: str = 'Sala Wykładowa'
|
name: str = 'Sala Wykładowa'
|
||||||
language: str ='pol'
|
language: str ='pol'
|
||||||
program_info: str = 'Sala Wykładowa PL'
|
program_info: str = 'Sala Wykładowa PL'
|
||||||
audio_source: str = 'file:./testdata/wave_particle_5min_pl.wav'
|
audio_source: str = 'file:./testdata/wave_particle_5min_pl.wav'
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -257,6 +257,20 @@ def run_async(async_command: Coroutine) -> None:
|
|||||||
color('!!! An error occurred while executing the command:', 'red'), message
|
color('!!! An error occurred while executing the command:', 'red'), message
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _build_bis_list(num_bis: int) -> list:
|
||||||
|
"""Build BIS list for BasicAudioAnnouncement based on num_bis (1=mono, 2=stereo)."""
|
||||||
|
locations = [bap.AudioLocation.FRONT_LEFT, bap.AudioLocation.FRONT_RIGHT]
|
||||||
|
return [
|
||||||
|
bap.BasicAudioAnnouncement.BIS(
|
||||||
|
index=idx + 1,
|
||||||
|
codec_specific_configuration=bap.CodecSpecificConfiguration(
|
||||||
|
audio_channel_allocation=locations[idx]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
for idx in range(num_bis)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
async def init_broadcast(
|
async def init_broadcast(
|
||||||
device,
|
device,
|
||||||
global_config : auracast_config.AuracastGlobalConfig,
|
global_config : auracast_config.AuracastGlobalConfig,
|
||||||
@@ -272,7 +286,8 @@ async def init_broadcast(
|
|||||||
tag=le_audio.Metadata.Tag.LANGUAGE, data=conf.language.encode()
|
tag=le_audio.Metadata.Tag.LANGUAGE, data=conf.language.encode()
|
||||||
),
|
),
|
||||||
le_audio.Metadata.Entry(
|
le_audio.Metadata.Entry(
|
||||||
tag=le_audio.Metadata.Tag.PROGRAM_INFO, data=conf.program_info.encode()
|
tag=le_audio.Metadata.Tag.PROGRAM_INFO,
|
||||||
|
data=conf.program_info.encode('latin-1')
|
||||||
),
|
),
|
||||||
le_audio.Metadata.Entry(
|
le_audio.Metadata.Entry(
|
||||||
tag=le_audio.Metadata.Tag.BROADCAST_NAME, data=conf.name.encode()
|
tag=le_audio.Metadata.Tag.BROADCAST_NAME, data=conf.name.encode()
|
||||||
@@ -295,9 +310,10 @@ async def init_broadcast(
|
|||||||
else []
|
else []
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logging.info(
|
try:
|
||||||
metadata.pretty_print("\n")
|
logging.info(metadata.pretty_print("\n"))
|
||||||
)
|
except UnicodeDecodeError:
|
||||||
|
logging.info("Metadata: (contains non-UTF-8 bytes)")
|
||||||
bigs[f'big{i}'] = {}
|
bigs[f'big{i}'] = {}
|
||||||
# Config advertising set
|
# Config advertising set
|
||||||
bigs[f'big{i}']['basic_audio_announcement'] = bap.BasicAudioAnnouncement(
|
bigs[f'big{i}']['basic_audio_announcement'] = bap.BasicAudioAnnouncement(
|
||||||
@@ -307,18 +323,11 @@ async def init_broadcast(
|
|||||||
codec_id=hci.CodingFormat(codec_id=hci.CodecID.LC3),
|
codec_id=hci.CodingFormat(codec_id=hci.CodecID.LC3),
|
||||||
codec_specific_configuration=bap.CodecSpecificConfiguration(
|
codec_specific_configuration=bap.CodecSpecificConfiguration(
|
||||||
sampling_frequency=bap_sampling_freq,
|
sampling_frequency=bap_sampling_freq,
|
||||||
frame_duration=bap.FrameDuration.DURATION_10000_US,
|
frame_duration=bap.FrameDuration.DURATION_7500_US if global_config.frame_duration_us == 7500 else bap.FrameDuration.DURATION_10000_US,
|
||||||
octets_per_codec_frame=global_config.octets_per_frame,
|
octets_per_codec_frame=global_config.octets_per_frame,
|
||||||
),
|
),
|
||||||
metadata=metadata,
|
metadata=metadata,
|
||||||
bis=[
|
bis=_build_bis_list(conf.num_bis),
|
||||||
bap.BasicAudioAnnouncement.BIS(
|
|
||||||
index=1,
|
|
||||||
codec_specific_configuration=bap.CodecSpecificConfiguration(
|
|
||||||
audio_channel_allocation=bap.AudioLocation.FRONT_LEFT
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -339,6 +348,36 @@ async def init_broadcast(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
bigs[f'big{i}']['broadcast_audio_announcement'] = bap.BroadcastAudioAnnouncement(conf.id)
|
bigs[f'big{i}']['broadcast_audio_announcement'] = bap.BroadcastAudioAnnouncement(conf.id)
|
||||||
|
|
||||||
|
# Build advertising data types list
|
||||||
|
advertising_data_types = [
|
||||||
|
(core.AdvertisingData.BROADCAST_NAME, conf.name.encode()),
|
||||||
|
]
|
||||||
|
|
||||||
|
# [PBP] Add Public Broadcast Profile Service Data (UUID 0x1856)
|
||||||
|
# Required for PTS Qualification (PBP/PBS/STR)
|
||||||
|
# Dynamically calculate PBP features based on stream configuration
|
||||||
|
pbp_features = 0x00
|
||||||
|
|
||||||
|
# Bit 0: Encryption (set if broadcast_code is configured)
|
||||||
|
if conf.code is not None:
|
||||||
|
pbp_features |= 0x01
|
||||||
|
|
||||||
|
# Bit 1 vs Bit 2: Quality based on sample rate
|
||||||
|
if global_config.auracast_sampling_rate_hz in [16000, 24000]:
|
||||||
|
pbp_features |= 0x02 # Standard Quality
|
||||||
|
elif global_config.auracast_sampling_rate_hz == 48000:
|
||||||
|
pbp_features |= 0x04 # High Quality
|
||||||
|
|
||||||
|
# Build PBP service data with Program_Info metadata (LTV format: Length, Type=0x03, Value)
|
||||||
|
# LTV: Length = 1 (type) + len(value), Type = 0x03 (Program_Info)
|
||||||
|
program_info_bytes = conf.program_info.encode('latin-1')
|
||||||
|
pbp_metadata_ltv = bytes([len(program_info_bytes) + 1, 0x03]) + program_info_bytes
|
||||||
|
pbp_service_data = struct.pack('<H', 0x1856) + bytes([pbp_features, len(pbp_metadata_ltv)]) + pbp_metadata_ltv
|
||||||
|
advertising_data_types.append(
|
||||||
|
(core.AdvertisingData.SERVICE_DATA_16_BIT_UUID, pbp_service_data)
|
||||||
|
)
|
||||||
|
|
||||||
advertising_set = await device.create_advertising_set(
|
advertising_set = await device.create_advertising_set(
|
||||||
random_address=hci.Address(conf.random_address),
|
random_address=hci.Address(conf.random_address),
|
||||||
advertising_parameters=bumble.device.AdvertisingParameters(
|
advertising_parameters=bumble.device.AdvertisingParameters(
|
||||||
@@ -355,11 +394,7 @@ async def init_broadcast(
|
|||||||
),
|
),
|
||||||
advertising_data=(
|
advertising_data=(
|
||||||
bigs[f'big{i}']['broadcast_audio_announcement'].get_advertising_data()
|
bigs[f'big{i}']['broadcast_audio_announcement'].get_advertising_data()
|
||||||
+ bytes(
|
+ bytes(core.AdvertisingData(advertising_data_types))
|
||||||
core.AdvertisingData(
|
|
||||||
[(core.AdvertisingData.BROADCAST_NAME, conf.name.encode())]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
+ advertising_manufacturer_data
|
+ advertising_manufacturer_data
|
||||||
),
|
),
|
||||||
periodic_advertising_parameters=bumble.device.PeriodicAdvertisingParameters(
|
periodic_advertising_parameters=bumble.device.PeriodicAdvertisingParameters(
|
||||||
@@ -384,7 +419,7 @@ async def init_broadcast(
|
|||||||
big = await device.create_big(
|
big = await device.create_big(
|
||||||
bigs[f'big{i}']['advertising_set'],
|
bigs[f'big{i}']['advertising_set'],
|
||||||
parameters=bumble.device.BigParameters(
|
parameters=bumble.device.BigParameters(
|
||||||
num_bis=1,
|
num_bis=conf.num_bis,
|
||||||
sdu_interval=global_config.qos_config.iso_int_multiple_10ms*10000, # Is the same as iso interval
|
sdu_interval=global_config.qos_config.iso_int_multiple_10ms*10000, # Is the same as iso interval
|
||||||
max_sdu=global_config.octets_per_frame,
|
max_sdu=global_config.octets_per_frame,
|
||||||
max_transport_latency=global_config.qos_config.max_transport_latency_ms,
|
max_transport_latency=global_config.qos_config.max_transport_latency_ms,
|
||||||
@@ -402,11 +437,18 @@ async def init_broadcast(
|
|||||||
direction=bis_link.Direction.HOST_TO_CONTROLLER
|
direction=bis_link.Direction.HOST_TO_CONTROLLER
|
||||||
)
|
)
|
||||||
|
|
||||||
iso_queue = bumble.device.IsoPacketStream(big.bis_links[0], conf.iso_que_len)
|
# Create ISO queue(s) - one per BIS
|
||||||
|
iso_queues = [
|
||||||
|
bumble.device.IsoPacketStream(link, conf.iso_que_len)
|
||||||
|
for link in big.bis_links
|
||||||
|
]
|
||||||
|
|
||||||
logging.info('Setup ISO Data Path')
|
logging.info('Setup ISO Data Path')
|
||||||
|
|
||||||
bigs[f'big{i}']['iso_queue'] = iso_queue
|
bigs[f'big{i}']['iso_queues'] = iso_queues
|
||||||
|
bigs[f'big{i}']['num_bis'] = conf.num_bis
|
||||||
|
# Keep backward compat: iso_queue points to first queue
|
||||||
|
bigs[f'big{i}']['iso_queue'] = iso_queues[0]
|
||||||
|
|
||||||
if global_config.debug:
|
if global_config.debug:
|
||||||
logging.info(f'big{i} parameters are:')
|
logging.info(f'big{i} parameters are:')
|
||||||
@@ -638,8 +680,16 @@ class Streamer():
|
|||||||
|
|
||||||
pcm_format = await audio_input.open()
|
pcm_format = await audio_input.open()
|
||||||
|
|
||||||
if pcm_format.channels != 1:
|
num_bis = big.get('num_bis', 1)
|
||||||
logging.info("Input device provides %d channels – will down-mix to mono for LC3", pcm_format.channels)
|
if num_bis == 2 and pcm_format.channels < 2:
|
||||||
|
logging.error("Stereo (num_bis=2) requires at least 2 input channels, got %d", pcm_format.channels)
|
||||||
|
return
|
||||||
|
if pcm_format.channels != num_bis:
|
||||||
|
if num_bis == 1:
|
||||||
|
logging.info("Input device provides %d channels – will down-mix to mono for LC3", pcm_format.channels)
|
||||||
|
else:
|
||||||
|
logging.info("Input device provides %d channels – using first %d for stereo", pcm_format.channels, num_bis)
|
||||||
|
|
||||||
if pcm_format.sample_type == audio_io.PcmFormat.SampleType.INT16:
|
if pcm_format.sample_type == audio_io.PcmFormat.SampleType.INT16:
|
||||||
pcm_bit_depth = 16
|
pcm_bit_depth = 16
|
||||||
elif pcm_format.sample_type == audio_io.PcmFormat.SampleType.FLOAT32:
|
elif pcm_format.sample_type == audio_io.PcmFormat.SampleType.FLOAT32:
|
||||||
@@ -648,20 +698,26 @@ class Streamer():
|
|||||||
logging.error("Only INT16 and FLOAT32 sample types are supported")
|
logging.error("Only INT16 and FLOAT32 sample types are supported")
|
||||||
return
|
return
|
||||||
|
|
||||||
encoder = lc3.Encoder(
|
# Create one encoder per BIS (mono: 1 encoder, stereo: 2 encoders)
|
||||||
frame_duration_us=global_config.frame_duration_us,
|
encoders = [
|
||||||
sample_rate_hz=global_config.auracast_sampling_rate_hz,
|
lc3.Encoder(
|
||||||
num_channels=1,
|
frame_duration_us=global_config.frame_duration_us,
|
||||||
input_sample_rate_hz=pcm_format.sample_rate,
|
sample_rate_hz=global_config.auracast_sampling_rate_hz,
|
||||||
)
|
num_channels=1,
|
||||||
|
input_sample_rate_hz=pcm_format.sample_rate,
|
||||||
|
)
|
||||||
|
for _ in range(num_bis)
|
||||||
|
]
|
||||||
|
|
||||||
lc3_frame_samples = encoder.get_frame_samples() # number of the pcm samples per lc3 frame
|
lc3_frame_samples = encoders[0].get_frame_samples() # number of the pcm samples per lc3 frame
|
||||||
big['pcm_bit_depth'] = pcm_bit_depth
|
big['pcm_bit_depth'] = pcm_bit_depth
|
||||||
big['channels'] = pcm_format.channels
|
big['channels'] = pcm_format.channels
|
||||||
big['lc3_frame_samples'] = lc3_frame_samples
|
big['lc3_frame_samples'] = lc3_frame_samples
|
||||||
big['lc3_bytes_per_frame'] = global_config.octets_per_frame
|
big['lc3_bytes_per_frame'] = global_config.octets_per_frame
|
||||||
big['audio_input'] = audio_input
|
big['audio_input'] = audio_input
|
||||||
big['encoder'] = encoder
|
big['encoders'] = encoders
|
||||||
|
# Keep backward compat
|
||||||
|
big['encoder'] = encoders[0]
|
||||||
big['precoded'] = False
|
big['precoded'] = False
|
||||||
|
|
||||||
logging.info("Streaming audio...")
|
logging.info("Streaming audio...")
|
||||||
@@ -686,8 +742,8 @@ class Streamer():
|
|||||||
# Ensure frames generator exists (so we can aclose() on stop)
|
# Ensure frames generator exists (so we can aclose() on stop)
|
||||||
frames_gen = big.get('frames_gen')
|
frames_gen = big.get('frames_gen')
|
||||||
if frames_gen is None:
|
if frames_gen is None:
|
||||||
|
# For stereo, request frame_samples per channel (interleaved input)
|
||||||
frames_gen = big['audio_input'].frames(big['lc3_frame_samples'])
|
frames_gen = big['audio_input'].frames(big['lc3_frame_samples'])
|
||||||
|
|
||||||
big['frames_gen'] = frames_gen
|
big['frames_gen'] = frames_gen
|
||||||
|
|
||||||
# Initialize perf tracking bucket per BIG
|
# Initialize perf tracking bucket per BIG
|
||||||
@@ -713,14 +769,31 @@ class Streamer():
|
|||||||
|
|
||||||
# Measure LC3 encoding time
|
# Measure LC3 encoding time
|
||||||
t1 = time.perf_counter()
|
t1 = time.perf_counter()
|
||||||
lc3_frame = big['encoder'].encode(
|
num_bis = big.get('num_bis', 1)
|
||||||
pcm_frame, num_bytes=big['lc3_bytes_per_frame'], bit_depth=big['pcm_bit_depth']
|
if num_bis == 1:
|
||||||
)
|
# Mono: single encoder, single queue
|
||||||
|
lc3_frame = big['encoder'].encode(
|
||||||
|
pcm_frame, num_bytes=big['lc3_bytes_per_frame'], bit_depth=big['pcm_bit_depth']
|
||||||
|
)
|
||||||
|
lc3_frames_out = [lc3_frame]
|
||||||
|
else:
|
||||||
|
# Stereo: split interleaved PCM into L/R, encode separately
|
||||||
|
pcm_array = np.frombuffer(pcm_frame, dtype=np.int16)
|
||||||
|
channels_in = big['channels']
|
||||||
|
lc3_frames_out = []
|
||||||
|
for ch_idx, encoder in enumerate(big['encoders']):
|
||||||
|
# Extract channel (interleaved: L,R,L,R,... or L,R,C,... for >2 ch)
|
||||||
|
ch_pcm = pcm_array[ch_idx::channels_in].tobytes()
|
||||||
|
lc3_frame = encoder.encode(
|
||||||
|
ch_pcm, num_bytes=big['lc3_bytes_per_frame'], bit_depth=big['pcm_bit_depth']
|
||||||
|
)
|
||||||
|
lc3_frames_out.append(lc3_frame)
|
||||||
dt_enc = time.perf_counter() - t1
|
dt_enc = time.perf_counter() - t1
|
||||||
|
|
||||||
# Measure write blocking time
|
# Measure write blocking time
|
||||||
t2 = time.perf_counter()
|
t2 = time.perf_counter()
|
||||||
await big['iso_queue'].write(lc3_frame)
|
for q_idx, lc3_frame in enumerate(lc3_frames_out):
|
||||||
|
await big['iso_queues'][q_idx].write(lc3_frame)
|
||||||
dt_write = time.perf_counter() - t2
|
dt_write = time.perf_counter() - t2
|
||||||
|
|
||||||
# Total loop duration
|
# Total loop duration
|
||||||
@@ -845,7 +918,7 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
|
|
||||||
# TODO: How can we use other iso interval than 10ms ?(medium or low rel) ? - nrf53audio receiver repports I2S tx underrun
|
# TODO: How can we use other iso interval than 10ms ?(medium or low rel) ? - nrf53audio receiver repports I2S tx underrun
|
||||||
config.qos_config=auracast_config.AuracastQosHigh()
|
config.qos_config=auracast_config.AuracastQosDefault()
|
||||||
|
|
||||||
#config.transport='serial:/dev/serial/by-id/usb-ZEPHYR_Zephyr_HCI_UART_sample_81BD14B8D71B5662-if00,1000000,rtscts' # transport for nrf52 dongle
|
#config.transport='serial:/dev/serial/by-id/usb-ZEPHYR_Zephyr_HCI_UART_sample_81BD14B8D71B5662-if00,1000000,rtscts' # transport for nrf52 dongle
|
||||||
#config.transport='serial:/dev/serial/by-id/usb-SEGGER_J-Link_001050076061-if02,1000000,rtscts' # transport for nrf53dk
|
#config.transport='serial:/dev/serial/by-id/usb-SEGGER_J-Link_001050076061-if02,1000000,rtscts' # transport for nrf53dk
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ async def main():
|
|||||||
os.chdir(os.path.dirname(__file__))
|
os.chdir(os.path.dirname(__file__))
|
||||||
|
|
||||||
global_conf = auracast_config.AuracastGlobalConfig(
|
global_conf = auracast_config.AuracastGlobalConfig(
|
||||||
qos_config=auracast_config.AuracastQosHigh()
|
qos_config=auracast_config.AuracastQosDefault()
|
||||||
)
|
)
|
||||||
#global_conf.transport='serial:/dev/serial/by-id/usb-SEGGER_J-Link_001057705357-if02,1000000,rtscts' # transport for nrf54l15dk
|
#global_conf.transport='serial:/dev/serial/by-id/usb-SEGGER_J-Link_001057705357-if02,1000000,rtscts' # transport for nrf54l15dk
|
||||||
global_conf.transport='serial:/dev/serial/by-id/usb-ZEPHYR_Zephyr_HCI_UART_sample_81BD14B8D71B5662-if00,115200,rtscts' #nrf52dongle hci_uart usb cdc
|
global_conf.transport='serial:/dev/serial/by-id/usb-ZEPHYR_Zephyr_HCI_UART_sample_81BD14B8D71B5662-if00,115200,rtscts' #nrf52dongle hci_uart usb cdc
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ if __name__ == "__main__":
|
|||||||
],
|
],
|
||||||
immediate_rendering=False,
|
immediate_rendering=False,
|
||||||
presentation_delay_us=40000,
|
presentation_delay_us=40000,
|
||||||
qos_config=auracast_config.AuracastQosHigh(),
|
qos_config=auracast_config.AuracastQosDefault(),
|
||||||
auracast_sampling_rate_hz = LC3_SRATE,
|
auracast_sampling_rate_hz = LC3_SRATE,
|
||||||
octets_per_frame = OCTETS_PER_FRAME,
|
octets_per_frame = OCTETS_PER_FRAME,
|
||||||
transport=TRANSPORT1,
|
transport=TRANSPORT1,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import os
|
|||||||
import asyncio
|
import asyncio
|
||||||
import logging as log
|
import logging as log
|
||||||
|
|
||||||
async def reset_nrf54l(slot: int = 0, timeout: float = 8.0):
|
async def reset_nrf54l(interface: int = 0, timeout: float = 8.0):
|
||||||
"""
|
"""
|
||||||
Reset the nRF54L target using OpenOCD before starting broadcast.
|
Reset the nRF54L target using OpenOCD before starting broadcast.
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ async def reset_nrf54l(slot: int = 0, timeout: float = 8.0):
|
|||||||
try:
|
try:
|
||||||
# Resolve project directory and filenames
|
# Resolve project directory and filenames
|
||||||
proj_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'openocd'))
|
proj_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'openocd'))
|
||||||
names = ['raspberrypi-swd0.cfg', 'swd0.cfg'] if slot == 0 else ['raspberrypi-swd1.cfg', 'swd1.cfg']
|
names = ['raspberrypi-swd0.cfg', 'swd0.cfg'] if interface == 0 else ['raspberrypi-swd1.cfg', 'swd1.cfg']
|
||||||
cfg = None
|
cfg = None
|
||||||
for n in names:
|
for n in names:
|
||||||
p = os.path.join(proj_dir, n)
|
p = os.path.join(proj_dir, n)
|
||||||
@@ -56,7 +56,7 @@ async def reset_nrf54l(slot: int = 0, timeout: float = 8.0):
|
|||||||
|
|
||||||
ok = await _run(cmd)
|
ok = await _run(cmd)
|
||||||
if ok:
|
if ok:
|
||||||
log.info("reset_nrf54l: reset succeeded (slot %d) using %s", slot, cfg)
|
log.info("reset_nrf54l: reset succeeded (interface %d) using %s", interface, cfg)
|
||||||
|
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
log.error("reset_nrf54l: openocd not found; skipping reset")
|
log.error("reset_nrf54l: openocd not found; skipping reset")
|
||||||
@@ -71,7 +71,10 @@ if __name__ == '__main__':
|
|||||||
format='%(asctime)s.%(msecs)03d %(levelname)s: %(message)s',
|
format='%(asctime)s.%(msecs)03d %(levelname)s: %(message)s',
|
||||||
datefmt='%Y-%m-%d %H:%M:%S'
|
datefmt='%Y-%m-%d %H:%M:%S'
|
||||||
)
|
)
|
||||||
|
interface_to_reset = 0
|
||||||
|
log.info(f"Executing reset for interface {interface_to_reset}")
|
||||||
|
asyncio.run(reset_nrf54l(interface=interface_to_reset))
|
||||||
|
|
||||||
slot_to_reset = 1
|
interface_to_reset = 1
|
||||||
log.info(f"Executing reset for slot {slot_to_reset}")
|
log.info(f"Executing reset for interface {interface_to_reset}")
|
||||||
asyncio.run(reset_nrf54l(slot=slot_to_reset))
|
asyncio.run(reset_nrf54l(interface=interface_to_reset))
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
adapter driver bcm2835gpio
|
adapter driver bcm2835gpio
|
||||||
transport select swd
|
transport select swd
|
||||||
adapter gpio swclk 17
|
adapter gpio swclk 17
|
||||||
adapter gpio swdio 18
|
adapter gpio swdio 26
|
||||||
#adapter gpio trst 26
|
#adapter gpio trst 26
|
||||||
#reset_config trst_only
|
#reset_config trst_only
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
adapter driver bcm2835gpio
|
adapter driver bcm2835gpio
|
||||||
transport select swd
|
transport select swd
|
||||||
adapter gpio swclk 24
|
adapter gpio swclk 23
|
||||||
adapter gpio swdio 23
|
adapter gpio swdio 24
|
||||||
#adapter gpio trst 27
|
#adapter gpio trst 27
|
||||||
#reset_config trst_only
|
#reset_config trst_only
|
||||||
|
|
||||||
|
|||||||
42
src/qualification/BAP/test_bap_bsrc_scc_bv20c.py
Normal file
42
src/qualification/BAP/test_bap_bsrc_scc_bv20c.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
"""
|
||||||
|
BAP/BSRC/SCC/BV-20-C: Config Broadcast, LC3 16_2_2
|
||||||
|
|
||||||
|
Configuration: 16kHz, 40 octets/frame, stereo (2 BISes), QoS _2 variant
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosDefault
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
# _2 variant uses different QoS (RTN=2, higher latency)
|
||||||
|
config.qos_config = AuracastQosDefault()
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
# 16_2_2: 16kHz, 40 octets/frame
|
||||||
|
config.auracast_sampling_rate_hz = 16000
|
||||||
|
config.octets_per_frame = 40
|
||||||
|
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_en.wav"
|
||||||
|
big.num_bis = 1
|
||||||
|
big.id = 12
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
42
src/qualification/BAP/test_bap_bsrc_scc_bv22c.py
Normal file
42
src/qualification/BAP/test_bap_bsrc_scc_bv22c.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
"""
|
||||||
|
BAP/BSRC/SCC/BV-22-C: Config Broadcast, LC3 24_2_2
|
||||||
|
|
||||||
|
Configuration: 24kHz, 60 octets/frame, stereo (2 BISes), QoS _2 variant
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosDefault
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
# _2 variant uses different QoS (RTN=2, higher latency)
|
||||||
|
config.qos_config = AuracastQosDefault()
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
# 24_2_2: 24kHz, 60 octets/frame
|
||||||
|
config.auracast_sampling_rate_hz = 24000
|
||||||
|
config.octets_per_frame = 60
|
||||||
|
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_en.wav"
|
||||||
|
big.num_bis = 1
|
||||||
|
big.id = 12
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
42
src/qualification/BAP/test_bap_bsrc_scc_bv28c.py
Normal file
42
src/qualification/BAP/test_bap_bsrc_scc_bv28c.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
"""
|
||||||
|
BAP/BSRC/SCC/BV-28-C: Config Broadcast, LC3 48_2_2
|
||||||
|
|
||||||
|
Configuration: 48kHz, 100 octets/frame, stereo (2 BISes), QoS _2 variant
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosDefault
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
# _2 variant uses different QoS (RTN=2, higher latency)
|
||||||
|
config.qos_config = AuracastQosDefault()
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
# 48_2_2: 48kHz, 100 octets/frame
|
||||||
|
config.auracast_sampling_rate_hz = 48000
|
||||||
|
config.octets_per_frame = 100
|
||||||
|
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_en.wav"
|
||||||
|
big.num_bis = 1
|
||||||
|
big.id = 12
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
42
src/qualification/BAP/test_bap_bsrc_scc_bv30c.py
Normal file
42
src/qualification/BAP/test_bap_bsrc_scc_bv30c.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
"""
|
||||||
|
BAP/BSRC/SCC/BV-30-C: Config Broadcast, LC3 48_4_2
|
||||||
|
|
||||||
|
Configuration: 48kHz, 120 octets/frame, stereo (2 BISes), QoS _2 variant
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosDefault
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
# _2 variant uses different QoS (RTN=2, higher latency)
|
||||||
|
config.qos_config = AuracastQosDefault()
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
# 48_4_2: 48kHz, 120 octets/frame
|
||||||
|
config.auracast_sampling_rate_hz = 48000
|
||||||
|
config.octets_per_frame = 120
|
||||||
|
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_en.wav"
|
||||||
|
big.num_bis = 1
|
||||||
|
big.id = 12
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
43
src/qualification/BAP/test_bap_bsrc_scc_bv32c.py
Normal file
43
src/qualification/BAP/test_bap_bsrc_scc_bv32c.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
"""
|
||||||
|
BAP/BSRC/SCC/BV-32-C: Config Broadcast, LC3 48_6_2
|
||||||
|
also works for BV35,36,37 - just restart
|
||||||
|
|
||||||
|
Configuration: 48kHz, 155 octets/frame, stereo (2 BISes), QoS _2 variant
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosDefault
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
# _2 variant uses different QoS (RTN=2, higher latency)
|
||||||
|
config.qos_config = AuracastQosDefault()
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
# 48_6_2: 48kHz, 155 octets/frame
|
||||||
|
config.auracast_sampling_rate_hz = 48000
|
||||||
|
config.octets_per_frame = 155
|
||||||
|
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_en.wav"
|
||||||
|
big.num_bis = 1
|
||||||
|
big.id = 12
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
45
src/qualification/BAP/test_bap_bsrc_scc_bv38c.py
Normal file
45
src/qualification/BAP/test_bap_bsrc_scc_bv38c.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
"""
|
||||||
|
BAP/BSRC/SCC/BV-38-C: Multi BIG Configuration
|
||||||
|
|
||||||
|
Configuration: Two BIGs (id=12 and id=13), stereo (2 BISes each)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosFast
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
config.qos_config = AuracastQosFast()
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
# First BIG
|
||||||
|
big1 = AuracastBigConfig()
|
||||||
|
big1.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big1.audio_source = "file:./testdata/announcement_en.wav"
|
||||||
|
big1.num_bis = 1
|
||||||
|
big1.id = 12
|
||||||
|
|
||||||
|
# Second BIG
|
||||||
|
big2 = AuracastBigConfig()
|
||||||
|
big2.random_address = "F1:F1:F2:F3:F4:F6"
|
||||||
|
big2.audio_source = "file:./testdata/announcement_en.wav"
|
||||||
|
big2.num_bis = 1
|
||||||
|
big2.id = 13
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big1, big2],
|
||||||
|
)
|
||||||
|
)
|
||||||
42
src/qualification/BAP/test_bap_bsrc_scc_str_bv04.py
Normal file
42
src/qualification/BAP/test_bap_bsrc_scc_str_bv04.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
"""
|
||||||
|
For BV36-C and BV 37-C to success just restart the stream while the testcase is running
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosDefault
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Ensure relative audio paths like in AuracastBigConfig work (./auracast/...) from src/auracast/
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
# Start from default global config
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
|
||||||
|
# Use same QoS profile as multicast main
|
||||||
|
config.qos_config = AuracastQosDefault()
|
||||||
|
|
||||||
|
# Transport similar to multicast main; adjust if needed for your setup
|
||||||
|
# config.transport = "auto" # let multicast auto-detect
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts" # Raspberry Pi default
|
||||||
|
|
||||||
|
# Default BIG, only modify the random address as requested
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_en.wav"
|
||||||
|
big.id = 12
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
41
src/qualification/BAP/test_bap_bsrc_scc_str_bv06c.py
Normal file
41
src/qualification/BAP/test_bap_bsrc_scc_str_bv06c.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
"""
|
||||||
|
BAP/BSRC/SCC/BV-06-C and BAP/BSRC/STR/BV-06-C: Config Broadcast, LC3 24_2_1
|
||||||
|
|
||||||
|
Configuration: 24kHz, stereo (2 BISes)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosFast
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
config.qos_config = AuracastQosFast()
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
# 24_2_1: 24kHz
|
||||||
|
config.auracast_sampling_rate_hz = 24000
|
||||||
|
config.octets_per_frame = 60
|
||||||
|
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_en.wav"
|
||||||
|
big.num_bis = 1
|
||||||
|
big.id = 12
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
41
src/qualification/BAP/test_bap_bsrc_scc_str_bv12c.py
Normal file
41
src/qualification/BAP/test_bap_bsrc_scc_str_bv12c.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
"""
|
||||||
|
BAP/BSRC/SCC/BV-12-C and BAP/BSRC/STR/BV-12-C: Config Broadcast, LC3 48_2_1
|
||||||
|
|
||||||
|
Configuration: 48kHz, 100 octets/frame, stereo (2 BISes)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosFast
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
config.qos_config = AuracastQosFast()
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
# 48_2_1: 48kHz, 100 octets/frame
|
||||||
|
config.auracast_sampling_rate_hz = 48000
|
||||||
|
config.octets_per_frame = 100
|
||||||
|
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_en.wav"
|
||||||
|
big.num_bis = 1
|
||||||
|
big.id = 12
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
41
src/qualification/BAP/test_bap_bsrc_scc_str_bv14c.py
Normal file
41
src/qualification/BAP/test_bap_bsrc_scc_str_bv14c.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
"""
|
||||||
|
BAP/BSRC/SCC/BV-14-C and BAP/BSRC/STR/BV-14-C: Config Broadcast, LC3 48_4_1
|
||||||
|
|
||||||
|
Configuration: 48kHz, 120 octets/frame, stereo (2 BISes)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosFast
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
config.qos_config = AuracastQosFast()
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
# 48_4_1: 48kHz, 120 octets/frame
|
||||||
|
config.auracast_sampling_rate_hz = 48000
|
||||||
|
config.octets_per_frame = 120
|
||||||
|
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_en.wav"
|
||||||
|
big.num_bis = 1
|
||||||
|
big.id = 12
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
41
src/qualification/BAP/test_bap_bsrc_scc_str_bv16c.py
Normal file
41
src/qualification/BAP/test_bap_bsrc_scc_str_bv16c.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
"""
|
||||||
|
BAP/BSRC/SCC/BV-16-C and BAP/BSRC/STR/BV-16-C: Config Broadcast, LC3 48_6_1
|
||||||
|
|
||||||
|
Configuration: 48kHz, 155 octets/frame, stereo (2 BISes)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosFast
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
config.qos_config = AuracastQosFast()
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
# 48_6_1: 48kHz, 155 octets/frame
|
||||||
|
config.auracast_sampling_rate_hz = 48000
|
||||||
|
config.octets_per_frame = 155
|
||||||
|
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_en.wav"
|
||||||
|
big.num_bis = 1
|
||||||
|
big.id = 12
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
41
src/qualification/BAP/test_bap_bsrc_str_bv21c.py
Normal file
41
src/qualification/BAP/test_bap_bsrc_str_bv21c.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
"""
|
||||||
|
BAP/BSRC/STR/BV-21-C: BSRC, Multiple BISes, LC3 16_2
|
||||||
|
|
||||||
|
Configuration: 16kHz, 40 octets/frame, stereo (2 BISes)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosFast
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
config.qos_config = AuracastQosFast()
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
# 16_2: 16kHz, 40 octets/frame
|
||||||
|
config.auracast_sampling_rate_hz = 16000
|
||||||
|
config.octets_per_frame = 40
|
||||||
|
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_es_stereo.wav"
|
||||||
|
big.id = 12
|
||||||
|
big.num_bis = 2 # stereo (multiple BISes)
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
41
src/qualification/BAP/test_bap_bsrc_str_bv23c.py
Normal file
41
src/qualification/BAP/test_bap_bsrc_str_bv23c.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
"""
|
||||||
|
BAP/BSRC/STR/BV-23-C: BSRC, Multiple BISes, LC3 24_2
|
||||||
|
|
||||||
|
Configuration: 24kHz, 60 octets/frame, stereo (2 BISes)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosFast
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
config.qos_config = AuracastQosFast()
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
# 24_2: 24kHz, 60 octets/frame
|
||||||
|
config.auracast_sampling_rate_hz = 24000
|
||||||
|
config.octets_per_frame = 60
|
||||||
|
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_es_stereo.wav"
|
||||||
|
big.id = 12
|
||||||
|
big.num_bis = 2 # stereo (multiple BISes)
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
41
src/qualification/BAP/test_bap_bsrc_str_bv29c.py
Normal file
41
src/qualification/BAP/test_bap_bsrc_str_bv29c.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
"""
|
||||||
|
BAP/BSRC/STR/BV-29-C: BSRC, Multiple BISes, LC3 48_2
|
||||||
|
|
||||||
|
Configuration: 48kHz, 100 octets/frame, stereo (2 BISes)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosFast
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
config.qos_config = AuracastQosFast()
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
# 48_2: 48kHz, 100 octets/frame
|
||||||
|
config.auracast_sampling_rate_hz = 48000
|
||||||
|
config.octets_per_frame = 100
|
||||||
|
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_es_stereo.wav"
|
||||||
|
big.id = 12
|
||||||
|
big.num_bis = 2 # stereo (multiple BISes)
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
41
src/qualification/BAP/test_bap_bsrc_str_bv31c.py
Normal file
41
src/qualification/BAP/test_bap_bsrc_str_bv31c.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
"""
|
||||||
|
BAP/BSRC/STR/BV-31-C: BSRC, Multiple BISes, LC3 48_4
|
||||||
|
|
||||||
|
Configuration: 48kHz, 120 octets/frame, stereo (2 BISes)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosFast
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
config.qos_config = AuracastQosFast()
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
# 48_4: 48kHz, 120 octets/frame
|
||||||
|
config.auracast_sampling_rate_hz = 48000
|
||||||
|
config.octets_per_frame = 120
|
||||||
|
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_es_stereo.wav"
|
||||||
|
big.id = 12
|
||||||
|
big.num_bis = 2 # stereo (multiple BISes)
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
41
src/qualification/BAP/test_bap_bsrc_str_bv33c.py
Normal file
41
src/qualification/BAP/test_bap_bsrc_str_bv33c.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
"""
|
||||||
|
BAP/BSRC/STR/BV-33-C: BSRC, Multiple BISes, LC3 48_6
|
||||||
|
|
||||||
|
Configuration: 48kHz, 155 octets/frame, stereo (2 BISes)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosFast
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
config.qos_config = AuracastQosFast()
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
# 48_6: 48kHz, 155 octets/frame
|
||||||
|
config.auracast_sampling_rate_hz = 48000
|
||||||
|
config.octets_per_frame = 155
|
||||||
|
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_es_stereo.wav"
|
||||||
|
big.id = 12
|
||||||
|
big.num_bis = 2 # stereo (multiple BISes)
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
46
src/qualification/CAP/test_cap_ini_bst.py
Normal file
46
src/qualification/CAP/test_cap_ini_bst.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
"""
|
||||||
|
CAP/INI/BST/BV-01-C and CAP/INI/BST/BV-05-C:
|
||||||
|
- BV-01-C: Broadcast Audio Starting for Single Audio Stream
|
||||||
|
- BV-05-C: Broadcast Audio Starting for Single Audio Streams - Single CCID
|
||||||
|
|
||||||
|
Make sure to set TSPX_BST_CODEC_CONFIG to 16_2_1
|
||||||
|
Restart the stream when asked to terminate.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosDefault
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
# Start from default global config
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
|
||||||
|
# Use same QoS profile as multicast main
|
||||||
|
config.qos_config = AuracastQosDefault()
|
||||||
|
|
||||||
|
# Transport similar to multicast main; adjust if needed for your setup
|
||||||
|
# config.transport = "auto" # let multicast auto-detect
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts" # Raspberry Pi default
|
||||||
|
|
||||||
|
# Default BIG, only modify the random address as requested
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_en.wav"
|
||||||
|
big.id = 12
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
42
src/qualification/GAP/test_gap_bis_bbm.py
Normal file
42
src/qualification/GAP/test_gap_bis_bbm.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
"""
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosDefault
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Ensure relative audio paths like in AuracastBigConfig work (./auracast/...) from src/auracast/
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
# Start from default global config
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
|
||||||
|
# Use same QoS profile as multicast main
|
||||||
|
config.qos_config = AuracastQosDefault()
|
||||||
|
|
||||||
|
# Transport similar to multicast main; adjust if needed for your setup
|
||||||
|
# config.transport = "auto" # let multicast auto-detect
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts" # Raspberry Pi default
|
||||||
|
|
||||||
|
# Stereo BIG with 2 BISes (FRONT_LEFT + FRONT_RIGHT)
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_es_stereo.wav"
|
||||||
|
big.id = 12
|
||||||
|
big.num_bis = 2 # stereo: 2 BISes
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
100
src/qualification/GAP/test_gap_brob_bcst.py
Normal file
100
src/qualification/GAP/test_gap_brob_bcst.py
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
"""
|
||||||
|
GAP/BROB/BCST/BV-01-C: Broadcaster role with non-connectable advertising.
|
||||||
|
|
||||||
|
Advertising with TSPX_advertising_data value (27 bytes):
|
||||||
|
- Flags: BR/EDR Not Supported
|
||||||
|
- 16-bit Service UUIDs: 0x1800, 0x1801
|
||||||
|
- Local Name: "PTS-GAP-06B8"
|
||||||
|
- Appearance: 0x0000
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
import bumble.device
|
||||||
|
import bumble.transport
|
||||||
|
from bumble import hci
|
||||||
|
from bumble.device import DeviceConfiguration, AdvertisingParameters, AdvertisingEventProperties
|
||||||
|
|
||||||
|
|
||||||
|
async def run_broadcaster():
|
||||||
|
"""Configure and start non-connectable advertising for GAP/BROB/BCST/BV-01-C."""
|
||||||
|
|
||||||
|
# Transport - adjust as needed for your setup
|
||||||
|
transport_str = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
async with await bumble.transport.open_transport(transport_str) as (hci_source, hci_sink):
|
||||||
|
# Device configuration
|
||||||
|
device_config = DeviceConfiguration(
|
||||||
|
name="PTS-GAP-06B8",
|
||||||
|
address=hci.Address("F1:F1:F2:F3:F4:F5"),
|
||||||
|
)
|
||||||
|
|
||||||
|
device = bumble.device.Device.from_config_with_hci(
|
||||||
|
device_config,
|
||||||
|
hci_source,
|
||||||
|
hci_sink,
|
||||||
|
)
|
||||||
|
await device.power_on()
|
||||||
|
|
||||||
|
# Exact advertising data payload (27 bytes) as specified:
|
||||||
|
# 0x02, 0x01, 0x04 - Flags: BR/EDR Not Supported
|
||||||
|
# 0x05, 0x03, 0x00, 0x18, 0x01, 0x18 - 16-bit Service UUIDs: 0x1800, 0x1801
|
||||||
|
# 0x0D, 0x09, 0x50, 0x54, 0x53, 0x2D, 0x47, - Complete Local Name: "PTS-GAP-06B8"
|
||||||
|
# 0x41, 0x50, 0x2D, 0x30, 0x36, 0x42, 0x38
|
||||||
|
# 0x03, 0x19, 0x00, 0x00 - Appearance: 0x0000
|
||||||
|
adv_data = bytes([
|
||||||
|
0x02, 0x01, 0x04, # Flags: BR/EDR Not Supported
|
||||||
|
0x05, 0x03, 0x00, 0x18, 0x01, 0x18, # 16-bit Service UUIDs
|
||||||
|
0x0D, 0x09, 0x50, 0x54, 0x53, 0x2D, 0x47, 0x41, # Local Name: "PTS-GAP-06B8"
|
||||||
|
0x50, 0x2D, 0x30, 0x36, 0x42, 0x38,
|
||||||
|
0x03, 0x19, 0x00, 0x00 # Appearance
|
||||||
|
])
|
||||||
|
|
||||||
|
logging.info("Advertising data (%d bytes): %s", len(adv_data), adv_data.hex())
|
||||||
|
|
||||||
|
# Create advertising set with non-connectable parameters (ADV_NONCONN_IND equivalent)
|
||||||
|
advertising_set = await device.create_advertising_set(
|
||||||
|
advertising_parameters=AdvertisingParameters(
|
||||||
|
advertising_event_properties=AdvertisingEventProperties(
|
||||||
|
is_connectable=False, # Non-connectable (ADV_NONCONN_IND)
|
||||||
|
is_scannable=False, # Not scannable
|
||||||
|
is_directed=False,
|
||||||
|
is_high_duty_cycle_directed_connectable=False,
|
||||||
|
is_legacy=True, # Use legacy advertising PDUs
|
||||||
|
is_anonymous=False,
|
||||||
|
),
|
||||||
|
primary_advertising_interval_min=0x0800, # 1.28s
|
||||||
|
primary_advertising_interval_max=0x0800, # 1.28s
|
||||||
|
primary_advertising_phy=hci.Phy.LE_1M,
|
||||||
|
),
|
||||||
|
advertising_data=adv_data,
|
||||||
|
auto_start=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
logging.info("Non-connectable advertising started (ADV_NONCONN_IND)")
|
||||||
|
logging.info("Advertising set handle: %s", advertising_set.advertising_handle)
|
||||||
|
|
||||||
|
# Keep advertising until interrupted
|
||||||
|
logging.info("Press Ctrl+C to stop...")
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
await advertising_set.stop()
|
||||||
|
logging.info("Advertising stopped")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
asyncio.run(run_broadcaster())
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
logging.info("Interrupted by user")
|
||||||
102
src/qualification/GAP/test_gap_conn_ncon.py
Normal file
102
src/qualification/GAP/test_gap_conn_ncon.py
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
"""
|
||||||
|
GAP/CONN/NCON/BV-01-C: Non-Connectable Mode.
|
||||||
|
|
||||||
|
PTS Action: Select YES when asked "Does the IUT have an ability to send
|
||||||
|
non-connectable advertising report?"
|
||||||
|
|
||||||
|
Configuration (same as GAP/BROB/BCST/BV-01-C):
|
||||||
|
- Advertising_Type: 0x03 (ADV_NONCONN_IND)
|
||||||
|
- Flags AD Type (0x01): 0x04 (Not Discoverable, BR/EDR Not Supported)
|
||||||
|
- Legacy non-connectable advertising packet
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
import bumble.device
|
||||||
|
import bumble.transport
|
||||||
|
from bumble import hci
|
||||||
|
from bumble.device import DeviceConfiguration, AdvertisingParameters, AdvertisingEventProperties
|
||||||
|
|
||||||
|
|
||||||
|
async def run_non_connectable():
|
||||||
|
"""Configure and start non-connectable advertising for GAP/CONN/NCON/BV-01-C."""
|
||||||
|
|
||||||
|
# Transport - adjust as needed for your setup
|
||||||
|
transport_str = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
async with await bumble.transport.open_transport(transport_str) as (hci_source, hci_sink):
|
||||||
|
# Device configuration
|
||||||
|
device_config = DeviceConfiguration(
|
||||||
|
name="PTS-GAP-06B8",
|
||||||
|
address=hci.Address("F1:F1:F2:F3:F4:F5"),
|
||||||
|
)
|
||||||
|
|
||||||
|
device = bumble.device.Device.from_config_with_hci(
|
||||||
|
device_config,
|
||||||
|
hci_source,
|
||||||
|
hci_sink,
|
||||||
|
)
|
||||||
|
await device.power_on()
|
||||||
|
|
||||||
|
# Exact advertising data payload (27 bytes) as specified:
|
||||||
|
# 0x02, 0x01, 0x04 - Flags: BR/EDR Not Supported
|
||||||
|
# 0x05, 0x03, 0x00, 0x18, 0x01, 0x18 - 16-bit Service UUIDs: 0x1800, 0x1801
|
||||||
|
# 0x0D, 0x09, 0x50, 0x54, 0x53, 0x2D, 0x47, - Complete Local Name: "PTS-GAP-06B8"
|
||||||
|
# 0x41, 0x50, 0x2D, 0x30, 0x36, 0x42, 0x38
|
||||||
|
# 0x03, 0x19, 0x00, 0x00 - Appearance: 0x0000
|
||||||
|
adv_data = bytes([
|
||||||
|
0x02, 0x01, 0x04, # Flags: BR/EDR Not Supported
|
||||||
|
0x05, 0x03, 0x00, 0x18, 0x01, 0x18, # 16-bit Service UUIDs
|
||||||
|
0x0D, 0x09, 0x50, 0x54, 0x53, 0x2D, 0x47, 0x41, # Local Name: "PTS-GAP-06B8"
|
||||||
|
0x50, 0x2D, 0x30, 0x36, 0x42, 0x38,
|
||||||
|
0x03, 0x19, 0x00, 0x00 # Appearance
|
||||||
|
])
|
||||||
|
|
||||||
|
logging.info("Advertising data (%d bytes): %s", len(adv_data), adv_data.hex())
|
||||||
|
|
||||||
|
# Create advertising set with non-connectable parameters (ADV_NONCONN_IND equivalent)
|
||||||
|
advertising_set = await device.create_advertising_set(
|
||||||
|
advertising_parameters=AdvertisingParameters(
|
||||||
|
advertising_event_properties=AdvertisingEventProperties(
|
||||||
|
is_connectable=False, # Non-connectable (ADV_NONCONN_IND)
|
||||||
|
is_scannable=False, # Not scannable
|
||||||
|
is_directed=False,
|
||||||
|
is_high_duty_cycle_directed_connectable=False,
|
||||||
|
is_legacy=True, # Use legacy advertising PDUs
|
||||||
|
is_anonymous=False,
|
||||||
|
),
|
||||||
|
primary_advertising_interval_min=0x0800, # 1.28s
|
||||||
|
primary_advertising_interval_max=0x0800, # 1.28s
|
||||||
|
primary_advertising_phy=hci.Phy.LE_1M,
|
||||||
|
),
|
||||||
|
advertising_data=adv_data,
|
||||||
|
auto_start=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
logging.info("Non-connectable advertising started (ADV_NONCONN_IND)")
|
||||||
|
logging.info("Advertising set handle: %s", advertising_set.advertising_handle)
|
||||||
|
|
||||||
|
# Keep advertising until interrupted
|
||||||
|
logging.info("Press Ctrl+C to stop...")
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
await advertising_set.stop()
|
||||||
|
logging.info("Advertising stopped")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
asyncio.run(run_non_connectable())
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
logging.info("Interrupted by user")
|
||||||
45
src/qualification/PBP/test_pbp_pbs_pbm_bv01c.py
Normal file
45
src/qualification/PBP/test_pbp_pbs_pbm_bv01c.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
"""
|
||||||
|
PBP/PBS/PBM/BV-01-C: Transmit Program_Info Metadata
|
||||||
|
|
||||||
|
Configuration: 16kHz, unencrypted, stereo (2 BISes)
|
||||||
|
Program_Info metadata: 0x00112233445566778899AABBCCDDEEFF
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosFast
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
config.qos_config = AuracastQosFast()
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
# 16_2_1: 16kHz, stereo
|
||||||
|
config.auracast_sampling_rate_hz = 16000
|
||||||
|
config.octets_per_frame = 40
|
||||||
|
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_en.wav"
|
||||||
|
big.num_bis = 1
|
||||||
|
big.id = 12
|
||||||
|
big.name = "Broadcast"
|
||||||
|
# Program_Info metadata: 00112233445566778899AABBCCDDEEFF
|
||||||
|
big.program_info = bytes.fromhex("00112233445566778899AABBCCDDEEFF").decode('latin-1')
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
45
src/qualification/PBP/test_pbp_pbs_str_bv01c.py
Normal file
45
src/qualification/PBP/test_pbp_pbs_str_bv01c.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
"""
|
||||||
|
PBP/PBS/STR/BV-01-C: Standard Quality Streaming Support, 16_2_1 - PBS
|
||||||
|
(TSPC_PBP_1_1 AND TSPC_PBP_7_1) OR TSPC_ALL
|
||||||
|
|
||||||
|
Configuration: 16kHz, unencrypted, stereo (2 BISes)
|
||||||
|
PBP Features: 0x02 (Standard Quality)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosFast
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
config.qos_config = AuracastQosFast()
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
# 16_2_1: 16kHz, stereo
|
||||||
|
config.auracast_sampling_rate_hz = 16000
|
||||||
|
config.octets_per_frame = 40
|
||||||
|
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_en.wav"
|
||||||
|
big.id = 12
|
||||||
|
big.num_bis = 1
|
||||||
|
big.name = "Broadcaster"
|
||||||
|
# Unencrypted (no code)
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
46
src/qualification/PBP/test_pbp_pbs_str_bv02c.py
Normal file
46
src/qualification/PBP/test_pbp_pbs_str_bv02c.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
"""
|
||||||
|
PBP/PBS/STR/BV-02-C: High Quality Streaming Support - PBS
|
||||||
|
(TSPC_PBP_1_1 AND TSPC_PBP_6_5) OR TSPC_ALL
|
||||||
|
|
||||||
|
Configuration: 48kHz, unencrypted, stereo (2 BISes)
|
||||||
|
PBP Features: 0x04 (High Quality)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosFast
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
config.qos_config = AuracastQosFast()
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
# High Quality: 48kHz, 48_1_1 configuration
|
||||||
|
config.auracast_sampling_rate_hz = 48000
|
||||||
|
config.octets_per_frame = 75 # 48_1_1: 48kHz, 75 octets/frame
|
||||||
|
config.frame_duration_us = 7500 # 7.5ms frame duration for 48_1_1
|
||||||
|
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_en.wav"
|
||||||
|
big.num_bis = 1
|
||||||
|
big.id = 12
|
||||||
|
big.name = "Broadcaster"
|
||||||
|
# Unencrypted (no code)
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
45
src/qualification/PBP/test_pbp_pbs_str_bv03c.py
Normal file
45
src/qualification/PBP/test_pbp_pbs_str_bv03c.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
"""
|
||||||
|
PBP/PBS/STR/BV-03-C: Encrypted Streaming Support, Standard Quality - PBS
|
||||||
|
(TSPC_PBP_1_1 AND TSPC_PBP_6_6 AND TSPC_PBP_6_4) OR TSPC_ALL
|
||||||
|
|
||||||
|
Configuration: 16kHz, encrypted, stereo (2 BISes)
|
||||||
|
PBP Features: 0x03 (Standard Quality + Encrypted)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosFast
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
config.qos_config = AuracastQosFast()
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
# Standard Quality: 16kHz
|
||||||
|
config.auracast_sampling_rate_hz = 16000
|
||||||
|
config.octets_per_frame = 40
|
||||||
|
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_en.wav"
|
||||||
|
big.num_bis = 1
|
||||||
|
big.id = 12
|
||||||
|
big.name = "Broadcaster"
|
||||||
|
big.code = "0x0102680553F1415AA265BBAFC6EA03B8" # Encrypted (hex format)
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
46
src/qualification/PBP/test_pbp_pbs_str_bv04c.py
Normal file
46
src/qualification/PBP/test_pbp_pbs_str_bv04c.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
"""
|
||||||
|
PBP/PBS/STR/BV-04-C: Encrypted Streaming Support, High Quality - PBS
|
||||||
|
(TSPC_PBP_1_1 AND TSPC_PBP_6_6 AND TSPC_PBP_6_5) OR TSPC_ALL
|
||||||
|
|
||||||
|
Configuration: 48kHz, encrypted, stereo (2 BISes)
|
||||||
|
PBP Features: 0x05 (High Quality + Encrypted)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosFast
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
config.qos_config = AuracastQosFast()
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
# High Quality: 48kHz, 48_1_1 configuration
|
||||||
|
config.auracast_sampling_rate_hz = 48000
|
||||||
|
config.octets_per_frame = 75 # 48_1_1: 48kHz, 75 octets/frame
|
||||||
|
config.frame_duration_us = 7500 # 7.5ms frame duration for 48_1_1
|
||||||
|
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_en.wav"
|
||||||
|
big.num_bis = 1
|
||||||
|
big.id = 12
|
||||||
|
big.name = "Broadcaster"
|
||||||
|
big.code = "0x0102680553F1415AA265BBAFC6EA03B8" # Encrypted (hex format)
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
46
src/qualification/PBP/test_pbp_pbs_str_bv05c.py
Normal file
46
src/qualification/PBP/test_pbp_pbs_str_bv05c.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
"""
|
||||||
|
PBP/PBS/STR/BV-05-C: Standard Quality Streaming Support, 16_2_2 - PBS
|
||||||
|
(TSPC_PBP_1_1 AND TSPC_PBP_7_3) OR TSPC_ALL
|
||||||
|
|
||||||
|
Configuration: 16kHz, unencrypted, stereo (2 BISes), QoS 16_2_2
|
||||||
|
PBP Features: 0x02 (Standard Quality)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosDefault
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
# 16_2_2 uses different QoS (RTN=2, higher latency)
|
||||||
|
config.qos_config = AuracastQosDefault()
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
# 16_2_2: 16kHz
|
||||||
|
config.auracast_sampling_rate_hz = 16000
|
||||||
|
config.octets_per_frame = 40
|
||||||
|
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_en.wav"
|
||||||
|
big.num_bis = 1
|
||||||
|
big.id = 12
|
||||||
|
big.name = "Broadcaster"
|
||||||
|
# Unencrypted (no code)
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
45
src/qualification/PBP/test_pbp_pbs_str_bv06c.py
Normal file
45
src/qualification/PBP/test_pbp_pbs_str_bv06c.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
"""
|
||||||
|
PBP/PBS/STR/BV-06-C: Standard Quality Streaming Support, 24_2_1 - PBS
|
||||||
|
(TSPC_PBP_1_1 AND TSPC_PBP_7_2) OR TSPC_ALL
|
||||||
|
|
||||||
|
Configuration: 24kHz, unencrypted, stereo (2 BISes)
|
||||||
|
PBP Features: 0x02 (Standard Quality)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosFast
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
config.qos_config = AuracastQosFast()
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
# 24_2_1: 24kHz
|
||||||
|
config.auracast_sampling_rate_hz = 24000
|
||||||
|
config.octets_per_frame = 60
|
||||||
|
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_en.wav"
|
||||||
|
big.num_bis = 1
|
||||||
|
big.id = 12
|
||||||
|
big.name = "Broadcaster"
|
||||||
|
# Unencrypted (no code)
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
46
src/qualification/PBP/test_pbp_pbs_str_bv07c.py
Normal file
46
src/qualification/PBP/test_pbp_pbs_str_bv07c.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
"""
|
||||||
|
PBP/PBS/STR/BV-07-C: Standard Quality Streaming Support, 24_2_2 - PBS
|
||||||
|
(TSPC_PBP_1_1 AND TSPC_PBP_7_4) OR TSPC_ALL
|
||||||
|
|
||||||
|
Configuration: 24kHz, unencrypted, stereo (2 BISes), QoS 24_2_2
|
||||||
|
PBP Features: 0x02 (Standard Quality)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosDefault
|
||||||
|
from auracast.multicast import broadcast, run_async
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(
|
||||||
|
level=os.environ.get("LOG_LEVEL", logging.INFO),
|
||||||
|
format="%(module)s.py:%(lineno)d %(levelname)s: %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
|
os.chdir(os.path.join(os.path.dirname(__file__), "../../auracast"))
|
||||||
|
|
||||||
|
config = AuracastGlobalConfig()
|
||||||
|
# 24_2_2 uses different QoS (RTN=2, higher latency)
|
||||||
|
config.qos_config = AuracastQosDefault()
|
||||||
|
config.transport = "serial:/dev/ttyAMA3,1000000,rtscts"
|
||||||
|
|
||||||
|
# 24_2_2: 24kHz
|
||||||
|
config.auracast_sampling_rate_hz = 24000
|
||||||
|
config.octets_per_frame = 60
|
||||||
|
|
||||||
|
big = AuracastBigConfig()
|
||||||
|
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||||
|
big.audio_source = "file:./testdata/announcement_en.wav"
|
||||||
|
big.num_bis = 1
|
||||||
|
big.id = 12
|
||||||
|
big.name = "Broadcaster"
|
||||||
|
# Unencrypted (no code)
|
||||||
|
|
||||||
|
run_async(
|
||||||
|
broadcast(
|
||||||
|
config,
|
||||||
|
[big],
|
||||||
|
)
|
||||||
|
)
|
||||||
33
src/qualification/README.md
Normal file
33
src/qualification/README.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Qualification procedure
|
||||||
|
|
||||||
|
# flash a qualifiaction dongle
|
||||||
|
- To use a normal nRF5240 Nordic dongle
|
||||||
|
- See https://bluekitchen-gmbh.com/bluetooth-pts-with-nordic-nrf52840-usb-dongle/ for Nordic nRF52 dev dongle
|
||||||
|
- Install PTS Firmware Upgrade Software
|
||||||
|
- Plug-in nRF52840 USB Dongle
|
||||||
|
- Start PTS Firmware Update Software
|
||||||
|
- If you click on 'OK', updating the bootloader will fail (the Nordic bootloader on the nRF52840 USB cannot be updated via DFU)
|
||||||
|
- Close the software
|
||||||
|
- Open an Explorer window and navigate to C:\Program Files (x86)\Bluetooth SIG\PTS Firmware Upgrade Software\tools and copy the file nrfutil.exe
|
||||||
|
- Navigate to AppData\Local\PTSFirmwareUpgradeSoftware within your user folder and paste the nrfutil.exe into this folder
|
||||||
|
- Note the file with the UUID128-like file name as you'll need it soon
|
||||||
|
- Open a PowerShell via File->Open Windows PowerShell as a regular user
|
||||||
|
- Reset the nRF52840 USB Dongle by pressing the smaller button (labeled 'RESET') to enter DFU mode
|
||||||
|
- A red LED should start flashing
|
||||||
|
- Run the nrfutil.exe with the .bin file (it's actually a ZIP archive) with the UUID128-like name
|
||||||
|
- Or just press the TAB key: .\nrfutil dfu usb-serial -pkg be4d3ab8-9c98-408a-8be4-18acf4b32d28.zip -p COM4
|
||||||
|
- Et voila, the nRF52840 USB Dongle can be used with PTS
|
||||||
|
|
||||||
|
# PTS ixit prerequisites
|
||||||
|
In BAP set
|
||||||
|
- Broadcast_ID=12
|
||||||
|
- Broadcast_ID_2=13
|
||||||
|
|
||||||
|
In CAP set
|
||||||
|
- TSPX_BST_CODEC_CONFIG=16_2_1
|
||||||
|
|
||||||
|
Everywhere set
|
||||||
|
- use STREAMING_DATA_CONFIRMATION_METHOD=By Playing
|
||||||
|
|
||||||
|
# Notes
|
||||||
|
- some testcases are just passed by restarting the stream.
|
||||||
Reference in New Issue
Block a user