Skip to content

Commit 5aff3fb

Browse files
committed
Set payload type of egress RTP packets WiP
1 parent 3efef1d commit 5aff3fb

File tree

3 files changed

+59
-22
lines changed

3 files changed

+59
-22
lines changed

lib/membrane_webrtc/ex_webrtc/sink.ex

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ defmodule Membrane.WebRTC.ExWebRTCSink do
2121
def_input_pad :input,
2222
accepted_format: Membrane.RTP,
2323
availability: :on_request,
24-
options: [kind: []]
24+
options: [kind: [], payload_type: [default: nil]]
2525

2626
@max_rtp_timestamp 2 ** 32 - 1
2727
@max_rtp_seq_num 2 ** 16 - 1
@@ -115,8 +115,8 @@ defmodule Membrane.WebRTC.ExWebRTCSink do
115115
end
116116

117117
@impl true
118-
def handle_buffer(pad, buffer, _ctx, state) do
119-
state = send_buffer(pad, buffer, state)
118+
def handle_buffer(pad, buffer, ctx, state) do
119+
state = send_buffer(pad, buffer, ctx, state)
120120
{[], state}
121121
end
122122

@@ -206,11 +206,12 @@ defmodule Membrane.WebRTC.ExWebRTCSink do
206206
state
207207
) do
208208
Membrane.Logger.debug("Received SDP answer")
209+
IO.puts("SDP ANSWER: \n" <> sdp.sdp <> "\n")
209210
:ok = PeerConnection.set_remote_description(state.pc, sdp)
210211

211212
%{negotiating_tracks: negotiating_tracks, negotiated_tracks: negotiated_tracks} = state
212213

213-
video_codecs = ExWebRTCUtils.get_video_codecs_from_sdp(sdp)
214+
video_codecs = ExWebRTCUtils.get_video_codecs_from_sdp(sdp) |> IO.inspect(label: "VIDEO CODECS FROM SDP")
214215

215216
to_notify =
216217
negotiating_tracks |> Enum.filter(& &1.notify) |> Enum.map(&Map.take(&1, [:id, :kind]))
@@ -266,12 +267,13 @@ defmodule Membrane.WebRTC.ExWebRTCSink do
266267
|> Enum.each(&PeerConnection.set_transceiver_direction(pc, &1.id, :sendonly))
267268

268269
{:ok, offer} = PeerConnection.create_offer(pc)
270+
# IO.puts("SDP OFFER: \n" <> offer.sdp <> "\n")
269271
:ok = PeerConnection.set_local_description(pc, offer)
270272
SignalingChannel.signal(state.signaling, offer)
271273
%{state | negotiating_tracks: negotiating_tracks, queued_tracks: []}
272274
end
273275

274-
defp send_buffer(pad, buffer, state) do
276+
defp send_buffer(pad, buffer, ctx, state) do
275277
{id, params} = state.input_tracks[pad]
276278

277279
timestamp =
@@ -288,6 +290,12 @@ defmodule Membrane.WebRTC.ExWebRTCSink do
288290
sequence_number: params.seq_num
289291
)
290292

293+
packet =
294+
case ctx.pads[pad].options.payload_type do
295+
int when is_integer(int) -> %{packet | payload_type: int}
296+
nil -> packet
297+
end
298+
291299
PeerConnection.send_rtp(state.pc, id, packet)
292300
seq_num = rem(params.seq_num + 1, @max_rtp_seq_num + 1)
293301
put_in(state.input_tracks[pad], {id, %{params | seq_num: seq_num}})

lib/membrane_webrtc/ex_webrtc/utils.ex

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,32 @@ defmodule Membrane.WebRTC.ExWebRTCUtils do
66
@type codec :: :opus | :h264 | :vp8
77
@type codec_or_codecs :: codec() | [codec()]
88

9+
@spec codec_payload_type(codec()) :: pos_integer()
10+
def codec_payload_type(:opus), do: 111
11+
def codec_payload_type(:h264), do: 96
12+
def codec_payload_type(:vp8), do: 102
13+
914
@spec codec_params(codec_or_codecs()) :: [RTPCodecParameters.t()]
1015
def codec_params(:opus),
1116
do: [
1217
%RTPCodecParameters{
13-
payload_type: 111,
18+
payload_type: codec_payload_type(:opus),
1419
mime_type: "audio/opus",
1520
clock_rate: codec_clock_rate(:opus),
1621
channels: 2
1722
}
1823
]
1924

2025
def codec_params(:h264) do
26+
payload_type = codec_payload_type(:h264)
27+
2128
[
2229
%RTPCodecParameters{
23-
payload_type: 96,
30+
payload_type: payload_type,
2431
mime_type: "video/H264",
2532
clock_rate: codec_clock_rate(:h264),
2633
sdp_fmtp_line: %ExSDP.Attribute.FMTP{
27-
pt: 96,
34+
pt: payload_type,
2835
level_asymmetry_allowed: 1,
2936
packetization_mode: 1,
3037
profile_level_id: 0x42E01F
@@ -36,7 +43,7 @@ defmodule Membrane.WebRTC.ExWebRTCUtils do
3643
def codec_params(:vp8) do
3744
[
3845
%RTPCodecParameters{
39-
payload_type: 102,
46+
payload_type: codec_payload_type(:vp8),
4047
mime_type: "video/VP8",
4148
clock_rate: codec_clock_rate(:vp8)
4249
}

lib/membrane_webrtc/sink.ex

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@ defmodule Membrane.WebRTC.Sink do
1616
the track received in `t:new_tracks/0` notification.
1717
"""
1818
use Membrane.Bin
19+
require Membrane.Logger
1920

2021
alias Membrane.H264
2122
alias Membrane.RemoteStream
2223
alias Membrane.VP8
23-
alias Membrane.WebRTC.{ExWebRTCSink, ForwardingFilter, SignalingChannel, SimpleWebSocketServer}
24+
alias Membrane.WebRTC.{ExWebRTCSink, ExWebRTCUtils, ForwardingFilter, SignalingChannel, SimpleWebSocketServer}
25+
26+
# alias __MODULE__.PayloadTypeSetter
2427

2528
@typedoc """
2629
Notification that should be sent to the bin to negotiate new tracks.
@@ -132,7 +135,7 @@ defmodule Membrane.WebRTC.Sink do
132135
end
133136

134137
@impl true
135-
def handle_pad_added(Pad.ref(:input, pid) = pad_ref, %{pad_options: %{kind: kind}}, state) do
138+
def handle_pad_added(Pad.ref(:input, id) = pad_ref, %{pad_options: %{kind: kind}}, state) do
136139
spec =
137140
cond do
138141
not state.payload_rtp ->
@@ -141,9 +144,11 @@ defmodule Membrane.WebRTC.Sink do
141144
|> get_child(:webrtc)
142145

143146
kind == :audio ->
147+
payload_type = ExWebRTCUtils.codec_payload_type(:opus)
148+
144149
bin_input(pad_ref)
145-
|> child({:rtp_opus_payloader, pid}, Membrane.RTP.Opus.Payloader)
146-
|> via_in(pad_ref, options: [kind: :audio])
150+
|> child({:rtp_opus_payloader, id}, Membrane.RTP.Opus.Payloader)
151+
|> via_in(pad_ref, options: [kind: :audio, payload_type: payload_type])
147152
|> get_child(:webrtc)
148153

149154
kind == :video ->
@@ -161,17 +166,19 @@ defmodule Membrane.WebRTC.Sink do
161166
_ctx,
162167
state
163168
) do
164-
payoader =
169+
{payloader, codec} =
165170
case stream_format do
166-
%H264{} -> %Membrane.RTP.H264.Payloader{max_payload_size: 1000}
167-
%VP8{} -> Membrane.RTP.VP8.Payloader
168-
%RemoteStream{content_format: VP8} -> Membrane.RTP.VP8.Payloader
171+
%H264{} ->{%Membrane.RTP.H264.Payloader{max_payload_size: 1000}, :h264}
172+
%VP8{} -> {Membrane.RTP.VP8.Payloader, :vp8}
173+
%RemoteStream{content_format: VP8} -> {Membrane.RTP.VP8.Payloader, :vp8}
169174
end
170175

176+
payload_type = ExWebRTCUtils.codec_payload_type(codec)
177+
171178
spec =
172179
get_child({:forwarding_filter, pad_ref})
173-
|> child({:rtp_payloader, pad_ref}, payoader)
174-
|> via_in(pad_ref, options: [kind: :video])
180+
|> child({:rtp_payloader, pad_ref}, payloader)
181+
|> via_in(pad_ref, options: [kind: :video, payload_type: payload_type])
175182
|> get_child(:webrtc)
176183

177184
{[spec: spec], state}
@@ -183,9 +190,24 @@ defmodule Membrane.WebRTC.Sink do
183190
end
184191

185192
@impl true
186-
def handle_child_notification({type, _content} = notification, :webrtc, _ctx, state)
187-
when type in [:new_tracks, :negotiated_video_codecs] do
188-
{[notify_parent: notification], state}
193+
def handle_child_notification({:negotiated_video_codecs, codecs}, :webrtc, _ctx, state) do
194+
if length(codecs) > 2 and state.payload_rtp do
195+
Membrane.Logger.warning("""
196+
Negotiated more then one video codec (#{inspect(codecs)}), while this bin will receive `Membrane.RTP` \
197+
packets on the input, with no information about codecs used to encode video streams. \
198+
Lack of this information might lead to setting inapropriate payload type of RTP packets and further \
199+
errors.
200+
201+
You can fix this problem by setting `:video_codec` option to `:vp8` or to `:h264`.
202+
""")
203+
end
204+
205+
{[notify_parent: {:negotiated_video_codecs, codecs}], state}
206+
end
207+
208+
@impl true
209+
def handle_child_notification({:new_tracks, new_tracks}, :webrtc, _ctx, state) do
210+
{[notify_parent: {:new_tracks, new_tracks}], state}
189211
end
190212

191213
@impl true

0 commit comments

Comments
 (0)