Skip to content

feat!: make voice receivers return AudioPacket classes instead of just Audio#11432

Merged
almeidx merged 12 commits into
discordjs:mainfrom
petergeneric:voice-rtp-headers
Jun 27, 2026
Merged

feat!: make voice receivers return AudioPacket classes instead of just Audio#11432
almeidx merged 12 commits into
discordjs:mainfrom
petergeneric:voice-rtp-headers

Conversation

@petergeneric

Copy link
Copy Markdown
Contributor

Currently, RTP packet headers are stripped and clients are only delivered Opus frames as Buffers. The lack of timestamp makes jitter/drift hard to combat for clients, who must compute wall-clock delivery time.

This change introduces an AudioPacket interface which extends Buffer with the following read-only fields:

  • sequence (16-bit uint monotonically increasing counter to allow for identifying out-of-order RTP packets)
  • timestamp (32-bit uint that counts encoder-side timestamps; RFC 7587, Opus in RTP requires this be expressed at 48kHz no matter the audio sample rate)
  • ssrc (to allow consumers to detect a change and reset their Opus decoder state; updates on this value can already be received via SSRCMap events, however I think it also belongs on AudioPacket because there's a risk of delayed SSRCMap event delivery, and the client needs to know as soon as they receive a packet that changes it so they can reset their decoder state to correctly parse the packet)

This change deliberately does not attempt to provide a generalised parser for all the fields in the RTP Header to keep this PR small and focused just on the essential fields.

@vercel

vercel Bot commented Feb 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Actions Updated (UTC)
discord-js Skipped Skipped Jun 27, 2026 3:40pm
discord-js-guide Skipped Skipped Jun 27, 2026 3:40pm

Request Review

@vercel vercel Bot temporarily deployed to Preview – discord-js February 27, 2026 23:11 Inactive
@vercel vercel Bot temporarily deployed to Preview – discord-js-guide February 27, 2026 23:11 Inactive
@petergeneric petergeneric changed the title Voice audio packets: Pass through RTP header values for Sequence, Timestamp, Sync Source feat: Voice audio packets: Pass through RTP header values for Sequence, Timestamp, Sync Source Feb 27, 2026
@coderabbitai

coderabbitai Bot commented Feb 27, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The changes extend audio packet handling in the voice receiver to include RTP metadata (sequence number, timestamp, and SSRC). A new public AudioPacket interface is introduced to expose this metadata, and the VoiceReceiver now wraps decrypted packets with these fields before streaming. Tests validate metadata extraction and backward compatibility.

Changes

Cohort / File(s) Summary
AudioPacket Interface Definition
packages/voice/src/receive/AudioReceiveStream.ts
Introduces new public interface AudioPacket extending Buffer with readonly properties for RTP sequence (16-bit), timestamp (32-bit), and SSRC (32-bit) identifiers.
Packet Metadata Wrapping
packages/voice/src/receive/VoiceReceiver.ts
Adds internal createAudioPacket helper function to attach RTP metadata as non-enumerable properties to decrypted buffers. Extracts sequence and timestamp from incoming UDP packet headers and wraps packets before streaming.
Metadata Extraction Tests
packages/voice/__tests__/VoiceReceiver.test.ts
Adds two new tests validating RTP metadata extraction from desktop/mobile RTP packets and confirming backward compatibility with existing packet handling.

Sequence Diagram

sequenceDiagram
    actor UDP as UDP Source
    participant VR as VoiceReceiver
    participant CAP as createAudioPacket
    participant ARS as AudioReceiveStream
    
    UDP->>VR: onUdpMessage (encrypted packet)
    Note over VR: Extract RTP sequence,<br/>timestamp from bytes
    VR->>VR: Decrypt packet payload
    VR->>CAP: createAudioPacket(buffer,<br/>sequence, timestamp, ssrc)
    CAP->>CAP: Attach metadata as<br/>non-enumerable properties
    CAP-->>VR: AudioPacket (Buffer + metadata)
    VR->>ARS: stream.push(AudioPacket)
    Note over ARS: Consumer receives<br/>Buffer with metadata
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description check ✅ Passed The description clearly explains the motivation (RTP headers were previously stripped), the solution (AudioPacket interface with sequence, timestamp, ssrc fields), and the rationale for scope limitation.
Title check ✅ Passed The title states 'make voice receivers return AudioPacket classes instead of just Audio', but the actual change introduces an AudioPacket interface (not a class) that wraps RTP header metadata into decrypted audio packets. The title is partially related but uses imprecise terminology ('classes' vs interface) and doesn't capture the core purpose: exposing RTP header fields (sequence, timestamp, ssrc).

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/voice/src/receive/AudioReceiveStream.ts`:
- Around line 39-41: Update the documentation for the AudioPacket buffer to
state it contains an Opus-encoded payload (with RTP header metadata) rather than
a "decoded Opus packet"; locate the AudioPacket type/comment in
AudioReceiveStream (or the AudioPacket JSDoc) and change the wording to
explicitly say "a Buffer containing an Opus-encoded payload with RTP header
metadata" so API consumers aren't misled.

In `@packages/voice/src/receive/VoiceReceiver.ts`:
- Around line 177-180: The RTP header reads in VoiceReceiver (variables
sequence, timestamp, ssrc reading from msg) can throw for 9–11 byte buffers;
change the early length guard to require at least 12 bytes (e.g., if (msg.length
< 12) return;) or move these reads inside the existing try that wraps
parsePacket so any RangeError is caught; update the check or relocate the reads
in the VoiceReceiver.ts function that computes sequence/timestamp/ssrc to ensure
no unhandled RangeError occurs.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0cb8be4 and f04d08b.

📒 Files selected for processing (3)
  • packages/voice/__tests__/VoiceReceiver.test.ts
  • packages/voice/src/receive/AudioReceiveStream.ts
  • packages/voice/src/receive/VoiceReceiver.ts
📜 Review details
🧰 Additional context used
🧬 Code graph analysis (2)
packages/voice/src/receive/VoiceReceiver.ts (1)
packages/voice/src/receive/AudioReceiveStream.ts (1)
  • AudioPacket (42-59)
packages/voice/__tests__/VoiceReceiver.test.ts (1)
packages/voice/__mocks__/rtp.ts (3)
  • RTP_PACKET_DESKTOP (7-16)
  • RTP_PACKET_CHROME (18-26)
  • RTP_PACKET_ANDROID (28-37)
🔇 Additional comments (2)
packages/voice/src/receive/VoiceReceiver.ts (1)

23-30: createAudioPacket wrapper is clean and backward-compatible.

Non-enumerable readonly metadata on Buffer is a good approach for preserving legacy buffer behavior.

packages/voice/__tests__/VoiceReceiver.test.ts (1)

71-110: Great coverage additions for metadata passthrough and compatibility.

These tests validate both RTP header field extraction and Buffer backward compatibility across multiple packet variants.

Comment thread packages/voice/src/receive/AudioReceiveStream.ts
Comment thread packages/voice/src/receive/VoiceReceiver.ts Outdated
@vercel vercel Bot temporarily deployed to Preview – discord-js February 27, 2026 23:37 Inactive
@vercel vercel Bot temporarily deployed to Preview – discord-js-guide February 27, 2026 23:37 Inactive
@petergeneric petergeneric changed the title feat: Voice audio packets: Pass through RTP header values for Sequence, Timestamp, Sync Source feat: pass rtp timestamp data through for audio packets Feb 27, 2026
@petergeneric petergeneric changed the title feat: pass rtp timestamp data through for audio packets feat: pass RTP timestamp data through for audio packets Feb 27, 2026
@vercel vercel Bot temporarily deployed to Preview – discord-js-guide February 27, 2026 23:46 Inactive
@vercel vercel Bot temporarily deployed to Preview – discord-js February 27, 2026 23:46 Inactive
@vercel vercel Bot temporarily deployed to Preview – discord-js February 28, 2026 01:07 Inactive
@vercel vercel Bot temporarily deployed to Preview – discord-js-guide February 28, 2026 01:07 Inactive
Comment thread packages/voice/src/receive/VoiceReceiver.ts Outdated
Comment thread packages/voice/src/receive/VoiceReceiver.ts Outdated
Comment thread packages/voice/src/receive/VoiceReceiver.ts Outdated
Comment thread packages/voice/src/receive/VoiceReceiver.ts Outdated
Comment thread packages/voice/src/receive/VoiceReceiver.ts Outdated
@vercel vercel Bot temporarily deployed to Preview – discord-js March 1, 2026 12:11 Inactive
@vercel vercel Bot temporarily deployed to Preview – discord-js-guide March 1, 2026 12:11 Inactive
@vercel vercel Bot temporarily deployed to Preview – discord-js March 1, 2026 12:18 Inactive
@vercel vercel Bot temporarily deployed to Preview – discord-js-guide March 1, 2026 12:18 Inactive
Comment thread packages/voice/src/receive/VoiceReceiver.ts Outdated
Comment thread packages/voice/src/receive/AudioReceiveStream.ts Outdated
@vercel vercel Bot temporarily deployed to Preview – discord-js-guide March 1, 2026 16:15 Inactive
@vercel vercel Bot temporarily deployed to Preview – discord-js March 1, 2026 16:15 Inactive
@petergeneric

Copy link
Copy Markdown
Contributor Author

@vladfrangu Looks like the other PR was created after the last comment on this PR, and (given I've been doing cleanup in this PR, and other changes as requested), the conflict is a bit annoying to me... I am willing to look into this but only if there's a path to actually getting this merged in quickly, it feels like it's just sitting in limbo

@petergeneric

Copy link
Copy Markdown
Contributor Author

@vladfrangu / @Qjuh what is happening with this PR?

@dominik1106

Copy link
Copy Markdown

Hey, sorry for bumping, but I'm also interested in the state of the PR since I'm facing similar issues with desync and as far as I can see, this should solve it

@petergeneric

Copy link
Copy Markdown
Contributor Author

@vladfrangu any update?

@vladfrangu

Copy link
Copy Markdown
Member

Sorry for the dead silence, can you get this PR rebased please? From my end these changes look good, I will take another quick look but should be all good

petergeneric and others added 11 commits May 23, 2026 00:53
…nd SSRC. Refactored so that instead of pure Buffer, we now send AudioPacket (interface extending Buffer) which has readonly fields sequence, timestamp, and ssrc.
 - Improve docstring use (also moved method to be private static to be more in-line with rest of code, and improved clarity of naming)
 - Fix pre-existing issue (min packet length was 8 bytes, but was expecting reading a uint32 at offset 8, so actual min length is 12)
 - Fix AudioPacket description
…r.ts

Co-authored-by: Qjuh <76154676+Qjuh@users.noreply.github.com>
…d fixing style to use hyphens. Also move addPacketHeaders to a bare function below the class per review comment
Minor naming changes as part of this because we are working with two Buffers (raw RTP packet, decrypted RTP/DAVE payload).
Change tests in VoiceReceiver.test.ts that were directly testing `decrypt` to instead test `parsePacket`
…er than an extension of Buffer. This breaks backwards-compatibility for existing AudioReceiveStream users, but is cleaner and allows for future extensibility.
… Documented constructor as not a public interface to discourage end-users from using it and breaking if we extend AudioPacket in the future
@vercel vercel Bot temporarily deployed to Preview – discord-js May 22, 2026 23:56 Inactive
@vercel vercel Bot temporarily deployed to Preview – discord-js-guide May 22, 2026 23:56 Inactive
@petergeneric

Copy link
Copy Markdown
Contributor Author

rebased with no conflicts, pr tests showing awaiting maintainer approval

Comment thread packages/voice/__tests__/VoiceReceiver.test.ts

@almeidx almeidx left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🤠

@github-project-automation github-project-automation Bot moved this from Todo to Review Approved in discord.js Jun 27, 2026
@vercel vercel Bot temporarily deployed to Preview – discord-js June 27, 2026 15:40 Inactive
@vercel vercel Bot temporarily deployed to Preview – discord-js-guide June 27, 2026 15:40 Inactive
@almeidx almeidx merged commit b9c59f7 into discordjs:main Jun 27, 2026
27 checks passed
@github-project-automation github-project-automation Bot moved this from Review Approved to Done in discord.js Jun 27, 2026
@Jiralite Jiralite added this to the voice 0.20.0 milestone Jun 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

6 participants