add PBP qualification tests and rename QoS profiles
- Rename AuracastQosHigh/Mid/Low to AuracastQosDefault/Fast for clarity - Add Public Broadcast Profile (PBP) service data to advertising with dynamic feature calculation based on encryption and sample rate - Add PBP/PBS/STR test cases (BV-01-C through BV-06-C) for standard and high quality streaming with various configurations - Update all existing test cases and main scripts to use new QoS profile names
This commit is contained in:
@@ -7,24 +7,19 @@ class AuracastQoSConfig(BaseModel):
|
||||
number_of_retransmissions: int
|
||||
max_transport_latency_ms: int
|
||||
|
||||
class AuracastQosHigh(AuracastQoSConfig):
|
||||
class AuracastQosDefault(AuracastQoSConfig):
|
||||
iso_int_multiple_10ms: int = 1
|
||||
number_of_retransmissions:int = 4 #4
|
||||
max_transport_latency_ms:int = 43 #varies from the default value in bumble (was 65)
|
||||
|
||||
class AuracastQosMid(AuracastQoSConfig):
|
||||
iso_int_multiple_10ms: int = 2
|
||||
number_of_retransmissions:int = 3
|
||||
max_transport_latency_ms:int = 65
|
||||
|
||||
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 AuracastQosFast(AuracastQoSConfig):
|
||||
iso_int_multiple_10ms: int = 1
|
||||
number_of_retransmissions:int = 2
|
||||
max_transport_latency_ms:int = 22
|
||||
|
||||
|
||||
class AuracastGlobalConfig(BaseModel):
|
||||
qos_config: AuracastQoSConfig = AuracastQosHigh()
|
||||
qos_config: AuracastQoSConfig = AuracastQosDefault()
|
||||
debug: bool = False
|
||||
device_name: str = 'Auracaster'
|
||||
transport: str = ''
|
||||
|
||||
@@ -346,6 +346,32 @@ async def init_broadcast(
|
||||
)
|
||||
)
|
||||
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
|
||||
|
||||
pbp_service_data = struct.pack('<H', 0x1856) + bytes([pbp_features, 0x00])
|
||||
advertising_data_types.append(
|
||||
(core.AdvertisingData.SERVICE_DATA_16_BIT_UUID, pbp_service_data)
|
||||
)
|
||||
|
||||
advertising_set = await device.create_advertising_set(
|
||||
random_address=hci.Address(conf.random_address),
|
||||
advertising_parameters=bumble.device.AdvertisingParameters(
|
||||
@@ -362,11 +388,7 @@ async def init_broadcast(
|
||||
),
|
||||
advertising_data=(
|
||||
bigs[f'big{i}']['broadcast_audio_announcement'].get_advertising_data()
|
||||
+ bytes(
|
||||
core.AdvertisingData(
|
||||
[(core.AdvertisingData.BROADCAST_NAME, conf.name.encode())]
|
||||
)
|
||||
)
|
||||
+ bytes(core.AdvertisingData(advertising_data_types))
|
||||
+ advertising_manufacturer_data
|
||||
),
|
||||
periodic_advertising_parameters=bumble.device.PeriodicAdvertisingParameters(
|
||||
@@ -890,7 +912,7 @@ if __name__ == "__main__":
|
||||
)
|
||||
|
||||
# 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-SEGGER_J-Link_001050076061-if02,1000000,rtscts' # transport for nrf53dk
|
||||
|
||||
@@ -140,7 +140,7 @@ async def main():
|
||||
os.chdir(os.path.dirname(__file__))
|
||||
|
||||
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-ZEPHYR_Zephyr_HCI_UART_sample_81BD14B8D71B5662-if00,115200,rtscts' #nrf52dongle hci_uart usb cdc
|
||||
|
||||
@@ -159,7 +159,7 @@ if __name__ == "__main__":
|
||||
],
|
||||
immediate_rendering=False,
|
||||
presentation_delay_us=40000,
|
||||
qos_config=auracast_config.AuracastQosHigh(),
|
||||
qos_config=auracast_config.AuracastQosDefault(),
|
||||
auracast_sampling_rate_hz = LC3_SRATE,
|
||||
octets_per_frame = OCTETS_PER_FRAME,
|
||||
transport=TRANSPORT1,
|
||||
|
||||
@@ -5,7 +5,7 @@ For BV36-C and BV 37-C to success just restart the stream while the testcase is
|
||||
import logging
|
||||
import os
|
||||
|
||||
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosHigh
|
||||
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosDefault
|
||||
from auracast.multicast import broadcast, run_async
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ if __name__ == "__main__":
|
||||
config = AuracastGlobalConfig()
|
||||
|
||||
# Use same QoS profile as multicast main
|
||||
config.qos_config = AuracastQosHigh()
|
||||
config.qos_config = AuracastQosDefault()
|
||||
|
||||
# Transport similar to multicast main; adjust if needed for your setup
|
||||
# config.transport = "auto" # let multicast auto-detect
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
"""
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosHigh
|
||||
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosDefault
|
||||
from auracast.multicast import broadcast, run_async
|
||||
|
||||
|
||||
@@ -21,7 +22,7 @@ if __name__ == "__main__":
|
||||
config = AuracastGlobalConfig()
|
||||
|
||||
# Use same QoS profile as multicast main
|
||||
config.qos_config = AuracastQosHigh()
|
||||
config.qos_config = AuracastQosDefault()
|
||||
|
||||
# Transport similar to multicast main; adjust if needed for your setup
|
||||
# config.transport = "auto" # let multicast auto-detect
|
||||
|
||||
@@ -6,7 +6,7 @@ restart the stream when asked to terminate.
|
||||
import logging
|
||||
import os
|
||||
|
||||
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosHigh
|
||||
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosDefault
|
||||
from auracast.multicast import broadcast, run_async
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ if __name__ == "__main__":
|
||||
config = AuracastGlobalConfig()
|
||||
|
||||
# Use same QoS profile as multicast main
|
||||
config.qos_config = AuracastQosHigh()
|
||||
config.qos_config = AuracastQosDefault()
|
||||
|
||||
# Transport similar to multicast main; adjust if needed for your setup
|
||||
# config.transport = "auto" # let multicast auto-detect
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import logging
|
||||
import os
|
||||
|
||||
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosHigh
|
||||
from auracast.auracast_config import AuracastGlobalConfig, AuracastBigConfig, AuracastQosDefault
|
||||
from auracast.multicast import broadcast, run_async
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ if __name__ == "__main__":
|
||||
config = AuracastGlobalConfig()
|
||||
|
||||
# Use same QoS profile as multicast main
|
||||
config.qos_config = AuracastQosHigh()
|
||||
config.qos_config = AuracastQosDefault()
|
||||
|
||||
# Transport similar to multicast main; adjust if needed for your setup
|
||||
# config.transport = "auto" # let multicast auto-detect
|
||||
|
||||
@@ -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_stereo.wav"
|
||||
big.id = 12
|
||||
big.num_bis = 2 # stereo
|
||||
big.name = "Broadcast"
|
||||
# Unencrypted (no code)
|
||||
|
||||
run_async(
|
||||
broadcast(
|
||||
config,
|
||||
[big],
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,45 @@
|
||||
"""
|
||||
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
|
||||
config.auracast_sampling_rate_hz = 48000
|
||||
config.octets_per_frame = 100 # 48kHz typical
|
||||
|
||||
big = AuracastBigConfig()
|
||||
big.random_address = "F1:F1:F2:F3:F4:F5"
|
||||
big.audio_source = "file:./testdata/announcement_en_stereo.wav"
|
||||
big.id = 12
|
||||
big.num_bis = 2 # stereo
|
||||
big.name = "Broadcast"
|
||||
# Unencrypted (no code)
|
||||
|
||||
run_async(
|
||||
broadcast(
|
||||
config,
|
||||
[big],
|
||||
)
|
||||
)
|
||||
@@ -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_stereo.wav"
|
||||
big.id = 12
|
||||
big.num_bis = 2 # stereo
|
||||
big.name = "Broadcast"
|
||||
big.code = "PBP_TEST_CODE" # Encrypted
|
||||
|
||||
run_async(
|
||||
broadcast(
|
||||
config,
|
||||
[big],
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,45 @@
|
||||
"""
|
||||
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
|
||||
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_stereo.wav"
|
||||
big.id = 12
|
||||
big.num_bis = 2 # stereo
|
||||
big.name = "Broadcast"
|
||||
big.code = "PBP_TEST_CODE" # Encrypted
|
||||
|
||||
run_async(
|
||||
broadcast(
|
||||
config,
|
||||
[big],
|
||||
)
|
||||
)
|
||||
@@ -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_stereo.wav"
|
||||
big.id = 12
|
||||
big.num_bis = 2 # stereo
|
||||
big.name = "Broadcast"
|
||||
# Unencrypted (no code)
|
||||
|
||||
run_async(
|
||||
broadcast(
|
||||
config,
|
||||
[big],
|
||||
)
|
||||
)
|
||||
@@ -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_stereo.wav"
|
||||
big.id = 12
|
||||
big.num_bis = 2 # stereo
|
||||
big.name = "Broadcast"
|
||||
# Unencrypted (no code)
|
||||
|
||||
run_async(
|
||||
broadcast(
|
||||
config,
|
||||
[big],
|
||||
)
|
||||
)
|
||||
@@ -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_stereo.wav"
|
||||
big.id = 12
|
||||
big.num_bis = 2 # stereo
|
||||
big.name = "Broadcast"
|
||||
# Unencrypted (no code)
|
||||
|
||||
run_async(
|
||||
broadcast(
|
||||
config,
|
||||
[big],
|
||||
)
|
||||
)
|
||||
Reference in New Issue
Block a user