fix(audio): copy Opus frame data before passing to consumer
DecodeOggOpus passes a slice from bytes.Buffer.Bytes() to the onFrame callback, then calls packet.Reset(). Reset reuses the underlying array, so when the next packet is assembled the previous slice's data is overwritten. In Discord voice playback the frames are sent to a buffered channel (OpusSend, cap 16); by the time opusSender reads a frame, its backing memory has been mutated by subsequent decoder iterations. The resulting Opus frame corruption causes audible artifacts: garbled or whispery audio depending on how much of each frame is overwritten before the voice sender transmits it. Fix: allocate a dedicated copy of each frame before handing it to the callback, decoupling the consumer's data from the reusable buffer. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
2e149f44dd
commit
989e5a554c
1 changed files with 10 additions and 4 deletions
|
|
@ -40,11 +40,17 @@ func DecodeOggOpus(r io.Reader, onFrame func([]byte) error) error {
|
|||
// If lacing is less than 255, the packet is complete
|
||||
if lacing < 255 {
|
||||
if packet.Len() > 0 {
|
||||
packetBytes := packet.Bytes()
|
||||
raw := packet.Bytes()
|
||||
// Ignore Ogg Opus headers
|
||||
if !bytes.HasPrefix(packetBytes, []byte("OpusHead")) &&
|
||||
!bytes.HasPrefix(packetBytes, []byte("OpusTags")) {
|
||||
if err := onFrame(packetBytes); err != nil {
|
||||
if !bytes.HasPrefix(raw, []byte("OpusHead")) &&
|
||||
!bytes.HasPrefix(raw, []byte("OpusTags")) {
|
||||
// Copy the frame data: packet.Reset() reuses the
|
||||
// underlying array, so the slice would be
|
||||
// overwritten by subsequent packets before the
|
||||
// consumer (e.g. OpusSend channel) reads it.
|
||||
frame := make([]byte, len(raw))
|
||||
copy(frame, raw)
|
||||
if err := onFrame(frame); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue