@@ -59,6 +59,7 @@ defmodule LiveExWebRTC.Player do
59
59
'''
60
60
use Phoenix.LiveView
61
61
62
+ require Logger
62
63
alias LiveExWebRTC.Player
63
64
64
65
@ type on_connected ( ) :: ( publisher_id :: String . t ( ) -> any ( ) )
@@ -87,7 +88,7 @@ defmodule LiveExWebRTC.Player do
87
88
video_codecs: nil ,
88
89
pc_genserver_opts: nil
89
90
90
- alias ExWebRTC . { ICECandidate , MediaStreamTrack , PeerConnection , SessionDescription }
91
+ alias ExWebRTC . { ICECandidate , MediaStreamTrack , PeerConnection , RTP.Munger , SessionDescription }
91
92
alias ExRTCP.Packet.PayloadFeedback.PLI
92
93
alias Phoenix.PubSub
93
94
@@ -193,7 +194,14 @@ defmodule LiveExWebRTC.Player do
193
194
@ impl true
194
195
def render ( assigns ) do
195
196
~H"""
197
+ < div class = "" >
196
198
< video id = { @ player . id } phx-hook = "Player " class = { @ class } controls autoplay muted > </ video >
199
+ < select id = "lexp-video-quality " >
200
+ < option value = "h " selected > High</ option >
201
+ < option value = "m " > Medium</ option >
202
+ < option value = "l " > Low</ option >
203
+ </ select >
204
+ </ div >
197
205
"""
198
206
end
199
207
@@ -208,7 +216,12 @@ defmodule LiveExWebRTC.Player do
208
216
socket =
209
217
receive do
210
218
{ ^ ref , % Player { publisher_id: ^ pub_id } = player } ->
211
- assign ( socket , player: player )
219
+ assign ( socket ,
220
+ player: player ,
221
+ munger: Munger . new ( 90_000 ) ,
222
+ layer: "h" ,
223
+ target_layer: "h"
224
+ )
212
225
after
213
226
5000 -> exit ( :timeout )
214
227
end
@@ -221,9 +234,9 @@ defmodule LiveExWebRTC.Player do
221
234
222
235
@ impl true
223
236
def handle_info ( { :ex_webrtc , _pid , { :connection_state_change , :connected } } , socket ) do
224
- % { player: player } = socket . assigns
237
+ % { player: player , layer: layer } = socket . assigns
225
238
PubSub . subscribe ( player . pubsub , "streams:audio:#{ player . publisher_id } " )
226
- PubSub . subscribe ( player . pubsub , "streams:video:#{ player . publisher_id } " )
239
+ PubSub . subscribe ( player . pubsub , "streams:video:#{ player . publisher_id } : #{ layer } " )
227
240
broadcast_keyframe_req ( socket )
228
241
if player . on_connected , do: player . on_connected . ( player . publisher_id )
229
242
@@ -256,16 +269,52 @@ defmodule LiveExWebRTC.Player do
256
269
{ :noreply , socket }
257
270
end
258
271
259
- def handle_info ( { :live_ex_webrtc , :video , packet } , socket ) do
272
+ def handle_info ( { :live_ex_webrtc , :video , rid , packet } , socket ) do
260
273
% { player: player } = socket . assigns
261
274
262
275
packet =
263
276
if player . on_packet ,
264
277
do: player . on_packet . ( player . publisher_id , :video , packet ) ,
265
278
else: packet
266
279
267
- PeerConnection . send_rtp ( player . pc , player . video_track_id , packet )
268
- { :noreply , socket }
280
+ cond do
281
+ rid == socket . assigns . layer ->
282
+ { packet , munger } = Munger . munge ( socket . assigns . munger , packet )
283
+ socket = assign ( socket , munger: munger )
284
+ :ok = PeerConnection . send_rtp ( player . pc , player . video_track_id , packet )
285
+ { :noreply , socket }
286
+
287
+ rid == socket . assigns . target_layer ->
288
+ if ExWebRTC.RTP.H264 . keyframe? ( packet ) == true do
289
+ munger = Munger . update ( socket . assigns . munger )
290
+ { packet , munger } = Munger . munge ( munger , packet )
291
+
292
+ PeerConnection . send_rtp ( player . pc , player . video_track_id , packet )
293
+
294
+ PubSub . unsubscribe (
295
+ socket . assigns . player . pubsub ,
296
+ "streams:video:#{ player . publisher_id } :#{ socket . assigns . layer } "
297
+ )
298
+
299
+ flush_layer ( socket . assigns . layer )
300
+
301
+ socket = assign ( socket , munger: munger , layer: rid )
302
+ { :noreply , socket }
303
+ else
304
+ { :noreply , socket }
305
+ end
306
+
307
+ true ->
308
+ # this should never happen
309
+ Logger . warning ( "unexpected unsubscribe" )
310
+
311
+ PubSub . unsubscribe (
312
+ socket . assigns . player . pubsub ,
313
+ "streams:video:#{ player . publisher_id } :#{ rid } "
314
+ )
315
+
316
+ { :noreply , socket }
317
+ end
269
318
end
270
319
271
320
@ impl true
@@ -334,6 +383,22 @@ defmodule LiveExWebRTC.Player do
334
383
end
335
384
end
336
385
386
+ @ impl true
387
+ def handle_event ( "layer" , layer , socket ) when layer in [ "l" , "m" , "h" ] do
388
+ if socket . assigns . layer == layer do
389
+ { :noreply , socket }
390
+ else
391
+ PubSub . subscribe (
392
+ socket . assigns . player . pubsub ,
393
+ "streams:video:#{ socket . assigns . player . publisher_id } :#{ layer } "
394
+ )
395
+
396
+ socket = assign ( socket , target_layer: layer )
397
+ broadcast_keyframe_req ( socket )
398
+ { :noreply , socket }
399
+ end
400
+ end
401
+
337
402
defp spawn_peer_connection ( socket ) do
338
403
% { player: player } = socket . assigns
339
404
@@ -363,10 +428,20 @@ defmodule LiveExWebRTC.Player do
363
428
defp broadcast_keyframe_req ( socket ) do
364
429
% { player: player } = socket . assigns
365
430
431
+ layer = socket . assigns . target_layer || socket . assigns . layer
432
+
366
433
PubSub . broadcast (
367
434
player . pubsub ,
368
435
"publishers:#{ player . publisher_id } " ,
369
- { :live_ex_webrtc , :keyframe_req }
436
+ { :live_ex_webrtc , :keyframe_req , layer }
370
437
)
371
438
end
439
+
440
+ defp flush_layer ( layer ) do
441
+ receive do
442
+ { :live_ex_webrtc , :video , ^ layer , _packet } -> flush_layer ( layer )
443
+ after
444
+ 0 -> :ok
445
+ end
446
+ end
372
447
end
0 commit comments