diff --git a/auracast/auracast_config.py b/auracast/auracast_config.py index 09cb5e1..50632d2 100644 --- a/auracast/auracast_config.py +++ b/auracast/auracast_config.py @@ -5,18 +5,18 @@ from dataclasses import dataclass # Define some base dataclasses to hold the relevant parameters @dataclass class AuracastQoSConfig: - iso_interval_us: int = 10000 - number_of_retransmissions:int = 4 - max_transport_latency_ms:int = 43 # TODO: varies from the default value in bumble (was 65) + 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) qos_config_mono_high_rel = AuracastQoSConfig() #highest rel + lowest latency qos_config_mono_medium_rel = AuracastQoSConfig( - iso_interval_us = 10000, + iso_int_multiple_10ms = 2, number_of_retransmissions = 3, max_transport_latency_ms = 65 ) qos_config_mono_low_rel = AuracastQoSConfig( #highest latency - iso_interval_us = 10000, + iso_int_multiple_10ms = 3, number_of_retransmissions = 2, max_transport_latency_ms = 65 ) diff --git a/auracast/multicast.py b/auracast/multicast.py index 5310978..3914fd5 100644 --- a/auracast/multicast.py +++ b/auracast/multicast.py @@ -84,7 +84,7 @@ async def create_device(config: auracast_config.AuracastGlobalConfig) -> AsyncGe name=config.device_name, address=config.auracast_device_address, keystore='JsonKeyStore', - #le_simultaneous_enabled=True #TODO: needed ? + #le_simultaneous_enabled=True #TODO: What is this doing ? ) device = bumble.device.Device.from_config_with_hci( @@ -141,7 +141,10 @@ async def run_broadcast( frames = list[bytes]() while pcm := wav.readframes(encoder.get_frame_samples()): frames.append( - encoder.encode(pcm, num_bytes=global_config.octets_per_frame, bit_depth=wav.getsampwidth() * 8) + encoder.encode( + pcm, + num_bytes=global_config.octets_per_frame, + bit_depth=wav.getsampwidth() * 8) ) del encoder logger.info('Encoding complete.') @@ -220,17 +223,23 @@ async def run_broadcast( await bigs[f'big{i}']['advertising_set'].start_periodic() logging.info('Setup BIG') + if global_config.qos_config.iso_int_multiple_10ms == 1: + frame_enable = 0 + else: + frame_enable = 1 + big = await device.create_big( bigs[f'big{i}']['advertising_set'] , parameters=bumble.device.BigParameters( num_bis=1, - sdu_interval=global_config.qos_config.iso_interval_us, - max_sdu=global_config.octets_per_frame, # is this octets per frame ? + 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_transport_latency=global_config.qos_config.max_transport_latency_ms, rtn=global_config.qos_config.number_of_retransmissions, broadcast_code=( bytes.fromhex(conf.broadcast_code) if conf.broadcast_code else None ), + framing=frame_enable # needed if iso interval is not frame interval of codedc ), ) bigs[f'big{i}']['big'] = big @@ -261,8 +270,12 @@ async def run_broadcast( event_found = False for big in bigs.values(): if big['big'].bis_links[0].handle == event_handle: - frame = next(big['frames_iterator']) + frame = b'' + for _ in range(0, global_config.qos_config.iso_int_multiple_10ms): + # loop is nececarry if iso interval is not frame interval of codec + frame += next(big['frames_iterator']) big['big'].bis_links[0].write(frame) + event_found = True if not event_found: logging.warning('unknown event on packet complete with handle: %s', event_handle) @@ -274,7 +287,7 @@ async def run_broadcast( # Send the first packet for each big, to get the event loop running for big in bigs.values(): - frame = next(big['frames_iterator'] ) + frame = next(big['frames_iterator']) big['big'].bis_links[0].write(frame) while True: @@ -298,7 +311,7 @@ def broadcast(global_conf: auracast_config.AuracastGlobalConfig, big_conf: List[ # ----------------------------------------------------------------------------- if __name__ == "__main__": logging.basicConfig( - level=logging.INFO, + level=logging.DEBUG, format='%(module)s.py:%(lineno)d %(levelname)s: %(message)s' ) @@ -310,28 +323,37 @@ if __name__ == "__main__": #global_conf.transport='serial:/dev/serial/by-id/usb-SEGGER_J-Link_001057705357-if02,1000000,rtscts' # transport for nrf54l15dk - global_conf.transport='serial:/dev/ttyACM1,115200,rtscts' + global_conf.transport='serial:/dev/serial/by-id/usb-ZEPHYR_Zephyr_HCI_UART_sample_81BD14B8D71B5662-if02,115200,rtscts' #nrf52dongle usb cdc uart - global_conf.qos_config = auracast_config.qos_config_mono_high_rel # TODO: low rel, actually advertising seems to work again- maybe then the problem is hci->controler + # TODO use nrf52dongle with hci over usb + + + # TODO: How can we use other iso interval than 10ms ?(medium or low rel) ? - nrf53audio receiver repports I2S tx underrun + global_conf.qos_config = auracast_config.qos_config_mono_medium_rel + + global_conf.qos_config = auracast_config.qos_config_mono_high_rel bigs = [ auracast_config.broadcast_de, auracast_config.broadcast_en, auracast_config.broadcast_fr, - auracast_config.broadcast_es, #TODO: spanish not appearing as auracast + auracast_config.broadcast_es, # auracast_config.broadcast_it, #TODO: with more than three broadcasts, not advertising at all is present, regardless the adv. interval - ] + ] # TODO: more than three broadcasters lead to some buffer overflow on hci side- try to increase some buffer lengths global_conf.auracast_sampling_rate_hz = 16000 global_conf.octets_per_frame = 40 # 32kbps@16kHz - # Note: 24kHz is only working with 2 streams - so this may be a host->controller interface bottleneck + # Note: 24kHz is only working with 2 streams - so this may be a host->controller interface bottleneck - probably airtime constraint + # 16kHz works reliably with 3 streams # use thread usage debugger on controller to check actual cpu load - not much load # TODO; I dont think hci is really the bottleneck. probably limited airtime is the problem. Analyze this somehow. # Advertising is still 1Mbit phy - use 2Mbit - # Check is the sdu interval (iso interval?) may really be varied - does not seem to work really + # Check is the sdu interval (iso interval?) may really be varied - does not seem to work really # # sdu per frame also needs to be adjusted somehow? is this even compatible with lc3? + # TODO: analyze the airtime somehow! + broadcast( global_conf, bigs