make dualcast work

This commit is contained in:
2025-02-06 12:01:43 +01:00
parent d9f210abe8
commit 9bf569d317
4 changed files with 42 additions and 21 deletions

View File

@@ -126,7 +126,7 @@ async def run_broadcast(
logger.info('Frame rate of .wav file is: %s', wav.getframerate()) logger.info('Frame rate of .wav file is: %s', wav.getframerate())
encoder = lc3.Encoder( encoder = lc3.Encoder(
frame_duration_us=global_config.frame_duration_us, frame_duration_us=global_config.frame_duration_us,
sample_rate_hz=global_config.auracast_sampling_rate_khz, sample_rate_hz=global_config.auracast_sampling_rate_hz,
num_channels=1, num_channels=1,
input_sample_rate_hz=wav.getframerate(), input_sample_rate_hz=wav.getframerate(),
) )
@@ -139,7 +139,7 @@ async def run_broadcast(
print('Encoding complete.') print('Encoding complete.')
# Config advertising set # Config advertising set
bap_sampling_freq = getattr(bap.SamplingFrequency, f"FREQ_{global_config.auracast_sampling_rate_khz}") bap_sampling_freq = getattr(bap.SamplingFrequency, f"FREQ_{global_config.auracast_sampling_rate_hz}")
basic_audio_announcement = bap.BasicAudioAnnouncement( basic_audio_announcement = bap.BasicAudioAnnouncement(
presentation_delay=global_config.presentation_delay_us, presentation_delay=global_config.presentation_delay_us,
subgroups=[ subgroups=[

View File

@@ -8,7 +8,7 @@ class AuracastGlobalConfig:
device_name: str = 'Auracaster' device_name: str = 'Auracaster'
transport: str = '' transport: str = ''
auracast_device_address: hci.Address = hci.Address('F0:F1:F2:F3:F4:F5') auracast_device_address: hci.Address = hci.Address('F0:F1:F2:F3:F4:F5')
auracast_sampling_rate_khz: int =24000 auracast_sampling_rate_hz: int = 24000
octets_per_frame: int = 100 # bitrate = octets_per_frame * 8 / frame len octets_per_frame: int = 100 # bitrate = octets_per_frame * 8 / frame len
frame_duration_us: int = 10000 frame_duration_us: int = 10000
presentation_delay_us: int = 40000 presentation_delay_us: int = 40000

View File

@@ -112,10 +112,13 @@ 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
) )
handle0 = None
handle1 = None
async def run_broadcast( async def run_broadcast(
global_config : auracast_config.AuracastGlobalConfig, global_config : auracast_config.AuracastGlobalConfig,
big_config: List[auracast_config.AuracastBigConfig] big_config: List[auracast_config.AuracastBigConfig]
) -> None: ) -> None:
async with create_device(global_config) as device: async with create_device(global_config) as device:
if not device.supports_le_periodic_advertising: if not device.supports_le_periodic_advertising:
@@ -128,7 +131,7 @@ async def run_broadcast(
logger.info('Frame rate of .wav file is: %s', wav.getframerate()) logger.info('Frame rate of .wav file is: %s', wav.getframerate())
encoder = lc3.Encoder( encoder = lc3.Encoder(
frame_duration_us=global_config.frame_duration_us, frame_duration_us=global_config.frame_duration_us,
sample_rate_hz=global_config.auracast_sampling_rate_khz, sample_rate_hz=global_config.auracast_sampling_rate_hz,
num_channels=1, num_channels=1,
input_sample_rate_hz=wav.getframerate(), input_sample_rate_hz=wav.getframerate(),
) )
@@ -141,7 +144,7 @@ async def run_broadcast(
print('Encoding complete.') print('Encoding complete.')
# Config advertising set # Config advertising set
bap_sampling_freq = getattr(bap.SamplingFrequency, f"FREQ_{global_config.auracast_sampling_rate_khz}") bap_sampling_freq = getattr(bap.SamplingFrequency, f"FREQ_{global_config.auracast_sampling_rate_hz}")
basic_audio_announcement0 = bap.BasicAudioAnnouncement( basic_audio_announcement0 = bap.BasicAudioAnnouncement(
presentation_delay=global_config.presentation_delay_us, presentation_delay=global_config.presentation_delay_us,
subgroups=[ subgroups=[
@@ -150,7 +153,7 @@ async def run_broadcast(
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_10000_US,
octets_per_codec_frame=global_config.octets_per_frame, octets_per_codec_frame=global_config.octets_per_frame,
), ),
metadata=le_audio.Metadata( metadata=le_audio.Metadata(
[ [
@@ -184,7 +187,7 @@ async def run_broadcast(
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_10000_US,
octets_per_codec_frame=global_config.octets_per_frame, octets_per_codec_frame=global_config.octets_per_frame,
), ),
metadata=le_audio.Metadata( metadata=le_audio.Metadata(
[ [
@@ -321,18 +324,36 @@ async def run_broadcast(
direction=bis_link.Direction.HOST_TO_CONTROLLER direction=bis_link.Direction.HOST_TO_CONTROLLER
) )
frames_iterator = itertools.cycle(frames) frames_iterator0 = itertools.cycle(frames)
frames_iterator1 = itertools.cycle(frames)
frame0 = next(frames_iterator0)
frame1 = next(frames_iterator1)
# Get the corresponding handles first
logging.info("Determine broadcast handles")
# Define on packet complete function to get the handle for each broadcast
handle0 = big0.bis_links[0].handle
handle1 = big1.bis_links[0].handle
logging.info("Broadcasting...") logging.info("Broadcasting...")
def on_packet_complete(event): def on_packet_complete(event):
frame = next(frames_iterator)
big0.bis_links[0].write(frame) event_handle = event.connection_handles[0]
if event_handle == handle0:
frame0 = next(frames_iterator0)
big0.bis_links[0].write(frame0)
elif event_handle == handle1:
frame1 = next(frames_iterator1)
big1.bis_links[0].write(frame1)
else:
raise NotImplementedError('Unkown connection handle')
device.host.on('hci_number_of_completed_packets_event', on_packet_complete) device.host.on('hci_number_of_completed_packets_event', on_packet_complete)
# Send the first packets, to get the event loop running
on_packet_complete('') # Send the first packet, to get the event loop running big0.bis_links[0].write(frame0)
big1.bis_links[0].write(frame1)
while True: while True:
await asyncio.sleep(1) await asyncio.sleep(1)
@@ -367,10 +388,10 @@ if __name__ == "__main__":
bigs = [ bigs = [
auracast_config.broadcast_de auracast_config.broadcast_de
] ]
global_conf.auracast_sampling_rate_khz=16000 #global_conf.auracast_sampling_rate_khz=16000
global_conf.octets_per_frame=40 # 16kbps@8kHz #global_conf.octets_per_frame=40 # 16kbps@8kHz
#global_conf.octets_per_frame=60# 48kbps@24kHz global_conf.octets_per_frame=60# 48kbps@24kHz
broadcast( broadcast(
global_conf, global_conf,

View File

@@ -125,7 +125,7 @@ async def run_broadcast(
logger.error(color('Periodic advertising not supported', 'red')) logger.error(color('Periodic advertising not supported', 'red'))
return return
bap_sampling_freq = getattr(bap.SamplingFrequency, f"FREQ_{global_config.auracast_sampling_rate_khz}") bap_sampling_freq = getattr(bap.SamplingFrequency, f"FREQ_{global_config.auracast_sampling_rate_hz}")
bigs = {} bigs = {}
for i, conf in enumerate(big_config): for i, conf in enumerate(big_config):
bigs[f'big{i}'] = {} bigs[f'big{i}'] = {}
@@ -134,7 +134,7 @@ async def run_broadcast(
logger.info('Frame rate of .wav file is: %s', wav.getframerate()) logger.info('Frame rate of .wav file is: %s', wav.getframerate())
encoder = lc3.Encoder( encoder = lc3.Encoder(
frame_duration_us=global_config.frame_duration_us, frame_duration_us=global_config.frame_duration_us,
sample_rate_hz=global_config.auracast_sampling_rate_khz, sample_rate_hz=global_config.auracast_sampling_rate_hz,
num_channels=1, num_channels=1,
input_sample_rate_hz=wav.getframerate(), input_sample_rate_hz=wav.getframerate(),
) )