-
-
Notifications
You must be signed in to change notification settings - Fork 76
Expand file tree
/
Copy pathrtp_parse.go
More file actions
129 lines (105 loc) · 3.04 KB
/
Copy pathrtp_parse.go
File metadata and controls
129 lines (105 loc) · 3.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// SPDX-License-Identifier: MPL-2.0
// SPDX-FileCopyrightText: Copyright (c) 2024, Emir Aganovic
package media
import (
"errors"
"fmt"
"io"
"github.com/pion/rtcp"
"github.com/pion/rtp"
)
var (
errRTCPFailedToUnmarshal = errors.New("rtcp: failed to unmarshal")
)
// Experimental
//
// RTPUnmarshal temporarly solution to provide more optimized unmarshal version based on pion/rtp
// it does not preserve any buffer reference which allows reusage
//
// TODO build RTP header unmarshaller for VOIP needs
func RTPUnmarshal(buf []byte, p *rtp.Packet) error {
n, err := p.Header.Unmarshal(buf)
if err != nil {
return err
}
return rtpUnmarshalPayload(n, buf, p)
}
func rtpUnmarshalPayload(n int, buf []byte, p *rtp.Packet) error {
if p.Header.Extension {
// For now eliminate it as it holds reference on buffer
// TODO fix this
p.Header.Extensions = nil
p.Header.Extension = false
}
end := len(buf)
if p.Header.Padding {
p.PaddingSize = buf[end-1]
end -= int(p.PaddingSize)
} else {
// Reset to 0 so a stale value from a previous packet (this *rtp.Packet
// is reused across reads) does not get subtracted in the downstream
// payloadSize calculation, which would truncate the payload. See #140.
p.PaddingSize = 0
}
if end < n {
return io.ErrShortBuffer
}
// If Payload buffer exists try to fill it and allow buffer reusage
if p.Payload != nil && len(p.Payload) >= len(buf[n:end]) {
copy(p.Payload, buf[n:end])
return nil
}
// This creates allocations
// Payload should be recreated instead referenced
// This allows buf reusage
p.Payload = make([]byte, len(buf[n:end]))
copy(p.Payload, buf[n:end])
return nil
}
// RTCPUnmarshal is improved version based on pion/rtcp where we allow caller to define and control
// buffer of rtcp packets. This also reduces one allocation
// NOTE: data is still referenced in packet buffer
func RTCPUnmarshal(data []byte, packets []rtcp.Packet) (n int, err error) {
for i := 0; i < len(packets) && len(data) != 0; i++ {
var h rtcp.Header
err = h.Unmarshal(data)
if err != nil {
// fmt.Errorf("unmarshal RTCP error: %w", err)
return 0, errors.Join(err, errRTCPFailedToUnmarshal)
}
pktLen := int(h.Length+1) * 4
if pktLen > len(data) {
return 0, fmt.Errorf("packet too short: %w", errRTCPFailedToUnmarshal)
}
inPacket := data[:pktLen]
// Check the type and unmarshal
packet := rtcpTypedPacket(h.Type)
err = packet.Unmarshal(inPacket)
if err != nil {
return 0, err
}
packets[i] = packet
data = data[pktLen:]
n++
}
return n, nil
}
func rtcpMarshal(packets []rtcp.Packet) ([]byte, error) {
return rtcp.Marshal(packets)
}
// TODO this would be nice that pion exports
func rtcpTypedPacket(htype rtcp.PacketType) rtcp.Packet {
// Currently we are not interested
switch htype {
case rtcp.TypeSenderReport:
return new(rtcp.SenderReport)
case rtcp.TypeReceiverReport:
return new(rtcp.ReceiverReport)
case rtcp.TypeSourceDescription:
return new(rtcp.SourceDescription)
case rtcp.TypeGoodbye:
return new(rtcp.Goodbye)
default:
return new(rtcp.RawPacket)
}
}