From 44cd517c859423a6624c7bbb72d508fab7e748b6 Mon Sep 17 00:00:00 2001 From: boks1971 Date: Fri, 1 May 2026 13:28:58 +0530 Subject: [PATCH 1/2] Add method to clear header extensions Adding a method to clear RTP header extensions. Also, modifying `DelExtension` to clear the extension flag if DelExtension will delete the last extension. --- packet.go | 11 +++++++++++ packet_test.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/packet.go b/packet.go index 8a91bc6..6d2c7f3 100644 --- a/packet.go +++ b/packet.go @@ -503,6 +503,10 @@ func (h *Header) DelExtension(id uint8) error { for i, extension := range h.Extensions { if extension.id == id { h.Extensions = append(h.Extensions[:i], h.Extensions[i+1:]...) + if len(h.Extensions) == 0 { + h.Extension = false + h.ExtensionProfile = 0 + } return nil } @@ -511,6 +515,13 @@ func (h *Header) DelExtension(id uint8) error { return errHeaderExtensionNotFound } +// ClearExtensions Removes all RTP Header extension. +func (h *Header) ClearExtensions() { + h.Extensions = h.Extensions[:0] + h.Extension = false + h.ExtensionProfile = 0 +} + // Marshal serializes the packet into bytes. func (p Packet) Marshal() (buf []byte, err error) { buf = make([]byte, p.MarshalSize()) diff --git a/packet_test.go b/packet_test.go index a868df7..8d9580e 100644 --- a/packet_test.go +++ b/packet_test.go @@ -680,6 +680,9 @@ func TestRFC8285DelExtension(t *testing.T) { {1, []byte{ 0xAA, }}, + {2, []byte{ + 0xBB, + }}, }, Version: 2, PayloadType: 96, @@ -693,6 +696,51 @@ func TestRFC8285DelExtension(t *testing.T) { assert.NoError(t, packet.DelExtension(1), "Should successfully delete extension") assert.Nil(t, packet.GetExtension(1), "Extension should not exist") assert.Error(t, packet.DelExtension(1), "Should return error when deleting extension that doesnt exist") + assert.True(t, packet.Extension, "Extension flag should not be cleared if extensions are still present") + assert.NotZero(t, packet.ExtensionProfile, "ExtensionProfile should have a valid extension profile type") + + assert.NotNil(t, packet.GetExtension(2), "Extension should exist") + assert.NoError(t, packet.DelExtension(2), "Should successfully delete extension") + assert.Nil(t, packet.GetExtension(2), "Extension should not exist") + assert.Error(t, packet.DelExtension(2), "Should return error when deleting extension that doesnt exist") + assert.False(t, packet.Extension, "Extension flag should be cleared if all extensions are deleted") + assert.Zero(t, packet.ExtensionProfile, "ExtensionProfile should be cleared") +} + +func TestRFC8285ClearExtensions(t *testing.T) { + payload := []byte{ + // Payload + 0x98, 0x36, 0xbe, 0x88, 0x9e, + } + packet := &Packet{ + Header: Header{ + Marker: true, + Extension: true, + ExtensionProfile: 0xBEDE, + Extensions: []Extension{ + {1, []byte{ + 0xAA, + }}, + {2, []byte{ + 0xBB, + }}, + }, + Version: 2, + PayloadType: 96, + SequenceNumber: 27023, + Timestamp: 3653407706, + SSRC: 476325762, + }, + Payload: payload, + } + assert.NotNil(t, packet.GetExtension(1), "Extension should exist") + assert.NotNil(t, packet.GetExtension(2), "Extension should exist") + packet.ClearExtensions() + assert.Nil(t, packet.GetExtension(1), "Extension should not exist") + assert.Nil(t, packet.GetExtension(2), "Extension should not exist") + assert.False(t, packet.Extension, "Extension flag should be cleared after clearing extensions") + assert.Zero(t, len(packet.Extensions), "Should not have any extensions") + assert.Zero(t, packet.ExtensionProfile, "ExtensionProfile should be reset") } func TestRFC8285GetExtensionIDs(t *testing.T) { From f6ea08a6d5e0e926409eba016c6fb359c36e1c18 Mon Sep 17 00:00:00 2001 From: boks1971 Date: Fri, 1 May 2026 14:35:11 +0530 Subject: [PATCH 2/2] Marshal should not have extension after delete --- packet_test.go | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/packet_test.go b/packet_test.go index 8d9580e..a607449 100644 --- a/packet_test.go +++ b/packet_test.go @@ -266,6 +266,44 @@ func TestBasic(t *testing.T) { // nolint:maintidx,cyclop buf, err = parsedPacket.Marshal() assert.NoError(t, err) assert.Equal(t, rawPkt, buf) + + // marshal packet after deleting extensions + rawPkt = []byte{ + 0xb0, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64, + 0x27, 0x82, 0xBE, 0xDE, 0x00, 0x01, 0x10, 0xAA, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x04, + } + parsedPacket = &Packet{ + Header: Header{ + Padding: true, + Marker: true, + Extension: true, + ExtensionProfile: 0xBEDE, + Extensions: []Extension{ + {1, []byte{ + 0xAA, + }}, + }, + Version: 2, + PayloadType: 96, + SequenceNumber: 27023, + Timestamp: 3653407706, + SSRC: 476325762, + PaddingSize: 4, + }, + Payload: rawPkt[20:21], + } + buf, err = parsedPacket.Marshal() + assert.NoError(t, err) + assert.Equal(t, rawPkt, buf) + assert.NoError(t, parsedPacket.DelExtension(1), "Should successfully delete extension") + // should not include extensions and X bit should be unset after deleting all extensions + rawPkt = []byte{ + 0xa0, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64, + 0x27, 0x82, 0x98, 0x00, 0x00, 0x00, 0x04, + } + buf, err = parsedPacket.Marshal() + assert.NoError(t, err) + assert.Equal(t, rawPkt, buf) } func TestExtension(t *testing.T) {