Replace in-memory LC3 file loading with streaming byte generator to reduce memory usage

Refactors LC3 file handling to stream frames byte-by-byte from disk instead of loading the entire file into memory. Adds _lc3_file_byte_gen generator function that skips the 18-byte LC3 header, reads frame size headers, and yields individual bytes with optional looping. Removes read_lc3_file usage and itertools.cycle approach in favor of the new streaming generator.
This commit is contained in:
2026-04-09 14:30:13 +02:00
parent 5f7fd1c0ff
commit 03d54eaddf

View File

@@ -551,6 +551,29 @@ async def init_broadcast(
return bigs
def _lc3_file_byte_gen(filename: str, loop: bool = False):
"""Stream LC3 frames from disk as individual bytes, with optional looping.
Yields one byte (int) at a time so it is compatible with the existing
``bytes(itertools.islice(gen, bytes_per_frame))`` consumer without loading
the whole file into memory.
"""
while True:
with open(filename, 'rb') as f:
f.read(18) # skip 18-byte LC3 header
while True:
size_b = f.read(2)
if len(size_b) < 2:
break
frame_size = struct.unpack('=H', size_b)[0]
frame = f.read(frame_size)
if len(frame) < frame_size:
break
yield from frame
if not loop:
return
class Streamer():
"""
Streamer class that supports multiple input formats. See bumble for streaming from wav or device
@@ -706,13 +729,7 @@ class Streamer():
big['precoded'] = True
big['lc3_bytes_per_frame'] = global_config.octets_per_frame
filename = big_config[i].audio_source.replace('file:', '')
lc3_bytes = read_lc3_file(filename)
lc3_frames = iter(lc3_bytes)
if big_config[i].loop:
lc3_frames = itertools.cycle(lc3_frames)
big['lc3_frames'] = lc3_frames
big['lc3_frames'] = _lc3_file_byte_gen(filename, loop=big_config[i].loop)
# use wav files and code them entirely before streaming
elif big_config[i].precode_wav and big_config[i].audio_source.endswith('.wav'):