@@ -2,6 +2,7 @@ defmodule ExWebRTC.RTP.Munger do
2
2
@ moduledoc """
3
3
RTP Munger allows for converting RTP packet timestamps and sequence numbers
4
4
to a common domain.
5
+ It also rewrites parts of the RTP payload that may require a similar behaviour.
5
6
6
7
This is useful when e.g. changing between Simulcast layers - the sender sends
7
8
three separate RTP streams (also called layers or encodings), but the receiver can receive only a
@@ -12,7 +13,7 @@ defmodule ExWebRTC.RTP.Munger do
12
13
# and this is a GenServer
13
14
14
15
def init() do
15
- {:ok, %{munger: Munger.new(90_000), layer: "h"}}
16
+ {:ok, %{munger: Munger.new(:h264, 90_000), layer: "h"}}
16
17
end
17
18
18
19
def handle_info({:ex_webrtc, _from, {:rtp, _id, rid, packet}}, state) do
@@ -34,6 +35,8 @@ defmodule ExWebRTC.RTP.Munger do
34
35
"""
35
36
36
37
alias ExRTP.Packet
38
+ alias ExWebRTC.RTPCodecParameters
39
+ alias ExWebRTC.RTP.VP8
37
40
38
41
@ max_rtp_ts 0xFFFFFFFF
39
42
@ max_rtp_sn 0xFFFF
@@ -47,14 +50,16 @@ defmodule ExWebRTC.RTP.Munger do
47
50
# * `sn_offset` - offset for sequence numbers
48
51
# * `ts_offset` - offset for timestamps
49
52
# * `update?` - flag telling if the next munged packets belongs to a new encoding
53
+ # * `vp8_munger` - VP8 munger, only used when RTP packets contain VP8 codec
50
54
@ opaque t ( ) :: % __MODULE__ {
51
55
clock_rate: non_neg_integer ( ) ,
52
56
rtp_sn: non_neg_integer ( ) | nil ,
53
57
rtp_ts: non_neg_integer ( ) | nil ,
54
58
wc_ts: integer ( ) | nil ,
55
59
sn_offset: integer ( ) ,
56
60
ts_offset: integer ( ) ,
57
- update?: boolean ( )
61
+ update?: boolean ( ) ,
62
+ vp8_munger: VP8.Munger . t ( ) | nil
58
63
}
59
64
60
65
@ enforce_keys [ :clock_rate ]
@@ -64,19 +69,31 @@ defmodule ExWebRTC.RTP.Munger do
64
69
:wc_ts ,
65
70
sn_offset: 0 ,
66
71
ts_offset: 0 ,
67
- update?: false
72
+ update?: false ,
73
+ vp8_munger: nil
68
74
] ++ @ enforce_keys
69
75
70
76
@ doc """
71
77
Creates a new `t:ExWebRTC.RTP.Munger.t/0`.
72
78
73
79
`clock_rate` is the clock rate of the codec carried in munged RTP packets.
74
80
"""
75
- @ spec new ( non_neg_integer ( ) ) :: t ( )
76
- def new ( clock_rate ) do
81
+ @ spec new ( :h264 | :vp8 | RTPCodecParameters . t ( ) , non_neg_integer ( ) ) :: t ( )
82
+ def new ( :h264 , clock_rate ) do
77
83
% __MODULE__ { clock_rate: clock_rate }
78
84
end
79
85
86
+ def new ( :vp8 , clock_rate ) do
87
+ % __MODULE__ { clock_rate: clock_rate , vp8_munger: VP8.Munger . new ( ) }
88
+ end
89
+
90
+ def new ( % RTPCodecParameters { } = codec_params ) do
91
+ case codec_params . mime_type do
92
+ "video/H264" -> new ( :h264 , codec_params . clock_rate )
93
+ "video/VP8" -> new ( :vp8 , codec_params . clock_rate )
94
+ end
95
+ end
96
+
80
97
@ doc """
81
98
Informs the munger that the next packet passed to `munge/2` will come
82
99
from a different RTP stream.
@@ -90,17 +107,30 @@ defmodule ExWebRTC.RTP.Munger do
90
107
@ spec munge ( t ( ) , Packet . t ( ) ) :: { Packet . t ( ) , t ( ) }
91
108
def munge ( % { rtp_sn: nil } = munger , packet ) do
92
109
# first packet ever munged
110
+ vp8_munger = munger . vp8_munger && VP8.Munger . init ( munger . vp8_munger , packet . payload )
111
+
93
112
munger = % __MODULE__ {
94
113
munger
95
114
| rtp_sn: packet . sequence_number ,
96
115
rtp_ts: packet . timestamp ,
97
- wc_ts: get_wc_ts ( packet )
116
+ wc_ts: get_wc_ts ( packet ) ,
117
+ vp8_munger: vp8_munger
98
118
}
99
119
100
120
{ packet , munger }
101
121
end
102
122
103
123
def munge ( munger , packet ) when munger . update? do
124
+ { vp8_munger , rtp_payload } =
125
+ if munger . vp8_munger do
126
+ vp8_munger = VP8.Munger . update ( munger . vp8_munger , packet . payload )
127
+ VP8.Munger . munge ( vp8_munger , packet . payload )
128
+ else
129
+ { munger . vp8_munger , packet . payload }
130
+ end
131
+
132
+ packet = % ExRTP.Packet { packet | payload: rtp_payload }
133
+
104
134
wc_ts = get_wc_ts ( packet )
105
135
106
136
native_in_sec = System . convert_time_unit ( 1 , :second , :native )
@@ -124,7 +154,8 @@ defmodule ExWebRTC.RTP.Munger do
124
154
| rtp_sn: new_packet . sequence_number ,
125
155
rtp_ts: new_packet . timestamp ,
126
156
wc_ts: wc_ts ,
127
- update?: false
157
+ update?: false ,
158
+ vp8_munger: vp8_munger
128
159
}
129
160
130
161
{ new_packet , munger }
@@ -135,6 +166,15 @@ defmodule ExWebRTC.RTP.Munger do
135
166
# the first packet after the encoding update
136
167
# as these might conflict with packets from the previous layer
137
168
# and we should change on a keyframe anyways
169
+ { vp8_munger , rtp_payload } =
170
+ if munger . vp8_munger do
171
+ VP8.Munger . munge ( munger . vp8_munger , packet . payload )
172
+ else
173
+ { munger . vp8_munger , packet . payload }
174
+ end
175
+
176
+ packet = % ExRTP.Packet { packet | payload: rtp_payload }
177
+
138
178
wc_ts = get_wc_ts ( packet )
139
179
140
180
new_packet = adjust_packet ( munger , packet )
@@ -148,10 +188,11 @@ defmodule ExWebRTC.RTP.Munger do
148
188
munger
149
189
| rtp_sn: new_packet . sequence_number ,
150
190
rtp_ts: new_packet . timestamp ,
151
- wc_ts: wc_ts
191
+ wc_ts: wc_ts ,
192
+ vp8_munger: vp8_munger
152
193
}
153
194
else
154
- munger
195
+ % __MODULE__ { munger | vp8_munger: vp8_munger }
155
196
end
156
197
157
198
{ new_packet , munger }
0 commit comments