Skip to content

fix(rtc): allocate total frame bytes in combine_audio_frames - #904

Open
NabiBukhsh-AI wants to merge 1 commit into
livekit:mainfrom
NabiBukhsh-AI:fix/rtc-combine-audio-frames-prealloc
Open

NabiBukhsh-AI wants to merge 1 commit into
livekit:mainfrom
NabiBukhsh-AI:fix/rtc-combine-audio-frames-prealloc

Conversation

@NabiBukhsh-AI

Copy link
Copy Markdown
Contributor

Summary

combine_audio_frames accumulates total_data_length to preallocate the destination bytearray before copying frame chunks in place:

total_data_length += len(frame.data)
...
data = bytearray(total_data_length)

However, frame.data is an int16 memoryview (format='h'). len(frame.data) returns the number of samples, not bytes. Because each 16-bit sample is 2 bytes, data = bytearray(total_data_length) preallocated exactly half the memory required for the combined frame.

During the copy loop:

frame_data = frame.data.cast("b")  # 2x bytes per sample
data[offset : offset + len(frame_data)] = frame_data

Python's bytearray slice assignment was forced to repeatedly grow and reallocate the underlying memory buffer on every frame, defeating the function's documented design:

"It efficiently merges the data by preallocating the necessary memory and copying the frame data without unnecessary reallocations."

Additionally, the docstring's example constructed AudioFrame(b"\x01\x02", 48000, 2, 1), which raises a ValueError because 2 channels with 1 sample per channel requires 4 bytes.

Changes

  • Used total_data_length += frame.data.nbytes so the preallocated bytearray accurately matches the total byte size of all frame buffers upfront.
  • Fixed the docstring example to use valid 16-bit PCM byte length and show combined_frame.data.tobytes().

Testing

Added unit test suite in tests/rtc/test_combine_audio_frames.py:

  • test_combine_audio_frames_allocates_exact_byte_size: verifies that the allocated bytearray size equals combined.data.nbytes (fails on main where it allocated half the required size).

  • test_combine_audio_frames_concatenates_samples_correctly: verifies sample concatenation.

  • test_combine_audio_frames_stereo: verifies multi-channel frames.

  • test_combine_audio_frames_single_frame: returns single frame as-is.

  • test_combine_audio_frames_empty_raises: raises ValueError on empty list.

  • test_combine_audio_frames_mismatched_sample_rate: raises ValueError on sample rate mismatch.

  • test_combine_audio_frames_mismatched_channels: raises ValueError on channel count mismatch.

  • test_combine_audio_frames_docstring_example: verifies the doctest example runs cleanly.

  • uv run pytest tests/rtc/test_combine_audio_frames.py -v -W error (8/8 passed)

  • uv run ruff check livekit-rtc/livekit/rtc/utils.py tests/rtc/test_combine_audio_frames.py (passed)

  • uv run ruff format --check livekit-rtc/livekit/rtc/utils.py tests/rtc/test_combine_audio_frames.py (passed)

  • uv run mypy livekit-rtc/livekit/rtc/utils.py tests/rtc/test_combine_audio_frames.py (0 issues)

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Devin Review

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant