@@ -60,6 +60,8 @@ defmodule LiveExWebRTC.Player do
60
60
use Phoenix.LiveView
61
61
62
62
require Logger
63
+ alias ExWebRTC.RTPCodecParameters
64
+ alias ExWebRTC.RTP . { H264 , VP8 }
63
65
alias LiveExWebRTC.Player
64
66
65
67
@ type on_connected ( ) :: ( publisher_id :: String . t ( ) -> any ( ) )
@@ -86,7 +88,12 @@ defmodule LiveExWebRTC.Player do
86
88
ice_port_range: nil ,
87
89
audio_codecs: nil ,
88
90
video_codecs: nil ,
89
- pc_genserver_opts: nil
91
+ pc_genserver_opts: nil ,
92
+ munger: nil ,
93
+ layer: nil ,
94
+ target_layer: nil ,
95
+ # codec that will be used for video sending
96
+ video_send_codec: nil
90
97
91
98
alias ExWebRTC . { ICECandidate , MediaStreamTrack , PeerConnection , RTP.Munger , SessionDescription }
92
99
alias ExRTCP.Packet.PayloadFeedback.PLI
@@ -219,12 +226,8 @@ defmodule LiveExWebRTC.Player do
219
226
socket =
220
227
receive do
221
228
{ ^ ref , % Player { publisher_id: ^ pub_id } = player } ->
222
- assign ( socket ,
223
- player: player ,
224
- munger: Munger . new ( 90_000 ) ,
225
- layer: "h" ,
226
- target_layer: "h"
227
- )
229
+ player = % Player { player | layer: "h" , target_layer: "h" }
230
+ assign ( socket , player: player )
228
231
after
229
232
5000 -> exit ( :timeout )
230
233
end
@@ -237,10 +240,18 @@ defmodule LiveExWebRTC.Player do
237
240
238
241
@ impl true
239
242
def handle_info ( { :ex_webrtc , _pid , { :connection_state_change , :connected } } , socket ) do
240
- % { player: player , layer: layer } = socket . assigns
241
- PubSub . subscribe ( player . pubsub , "streams:audio:#{ player . publisher_id } " )
242
- PubSub . subscribe ( player . pubsub , "streams:video:#{ player . publisher_id } :#{ layer } " )
243
- broadcast_keyframe_req ( socket )
243
+ % { player: player } = socket . assigns
244
+
245
+ # subscribe only if we managed to negotiate tracks
246
+ if player . audio_track_id != nil do
247
+ PubSub . subscribe ( player . pubsub , "streams:audio:#{ player . publisher_id } " )
248
+ end
249
+
250
+ if player . video_track_id != nil do
251
+ PubSub . subscribe ( player . pubsub , "streams:video:#{ player . publisher_id } :#{ player . layer } " )
252
+ broadcast_keyframe_req ( socket )
253
+ end
254
+
244
255
if player . on_connected , do: player . on_connected . ( player . publisher_id )
245
256
246
257
{ :noreply , socket }
@@ -281,27 +292,29 @@ defmodule LiveExWebRTC.Player do
281
292
else: packet
282
293
283
294
cond do
284
- rid == socket . assigns . layer ->
285
- { packet , munger } = Munger . munge ( socket . assigns . munger , packet )
286
- socket = assign ( socket , munger: munger )
295
+ rid == player . layer ->
296
+ { packet , munger } = Munger . munge ( player . munger , packet )
297
+ player = % Player { player | munger: munger }
298
+ socket = assign ( socket , player: player )
287
299
:ok = PeerConnection . send_rtp ( player . pc , player . video_track_id , packet )
288
300
{ :noreply , socket }
289
301
290
- rid == socket . assigns . target_layer ->
291
- if ExWebRTC.RTP.H264 . keyframe? ( packet ) == true do
292
- munger = Munger . update ( socket . assigns . munger )
302
+ rid == player . target_layer ->
303
+ if keyframe? ( player . video_send_codec , packet ) == true do
304
+ munger = Munger . update ( player . munger )
293
305
{ packet , munger } = Munger . munge ( munger , packet )
294
306
295
307
PeerConnection . send_rtp ( player . pc , player . video_track_id , packet )
296
308
297
309
PubSub . unsubscribe (
298
310
socket . assigns . player . pubsub ,
299
- "streams:video:#{ player . publisher_id } :#{ socket . assigns . layer } "
311
+ "streams:video:#{ player . publisher_id } :#{ player . layer } "
300
312
)
301
313
302
- flush_layer ( socket . assigns . layer )
314
+ flush_layer ( player . layer )
303
315
304
- socket = assign ( socket , munger: munger , layer: rid )
316
+ player = % Player { player | munger: munger , layer: rid }
317
+ socket = assign ( socket , player: player )
305
318
{ :noreply , socket }
306
319
else
307
320
{ :noreply , socket }
@@ -332,18 +345,28 @@ defmodule LiveExWebRTC.Player do
332
345
stream_id = MediaStreamTrack . generate_stream_id ( )
333
346
audio_track = MediaStreamTrack . new ( :audio , [ stream_id ] )
334
347
video_track = MediaStreamTrack . new ( :video , [ stream_id ] )
335
- { :ok , _sender } = PeerConnection . add_track ( pc , audio_track )
336
- { :ok , _sender } = PeerConnection . add_track ( pc , video_track )
348
+ { :ok , audio_sender } = PeerConnection . add_track ( pc , audio_track )
349
+ { :ok , video_sender } = PeerConnection . add_track ( pc , video_track )
337
350
{ :ok , answer } = PeerConnection . create_answer ( pc )
338
351
:ok = PeerConnection . set_local_description ( pc , answer )
339
352
:ok = gather_candidates ( pc )
340
353
answer = PeerConnection . get_local_description ( pc )
341
354
355
+ transceivers = PeerConnection . get_transceivers ( pc )
356
+ video_tr = Enum . find ( transceivers , fn tr -> tr . sender . id == video_sender . id end )
357
+ audio_tr = Enum . find ( transceivers , fn tr -> tr . sender . id == audio_sender . id end )
358
+
359
+ # check if tracks were negotiated successfully
360
+ video_negotiated? = video_tr && video_tr . direction == :sendrecv
361
+ audio_negotiated? = audio_tr && audio_tr . direction == :sendrecv
362
+
342
363
new_player = % Player {
343
364
player
344
365
| pc: pc ,
345
- audio_track_id: audio_track . id ,
346
- video_track_id: video_track . id
366
+ audio_track_id: audio_negotiated? && audio_track . id ,
367
+ video_track_id: video_negotiated? && video_track . id ,
368
+ munger: video_negotiated? && Munger . new ( List . first ( video_tr . codecs ) ) ,
369
+ video_send_codec: List . first ( video_tr . codecs )
347
370
}
348
371
349
372
{ :noreply ,
@@ -388,15 +411,19 @@ defmodule LiveExWebRTC.Player do
388
411
389
412
@ impl true
390
413
def handle_event ( "layer" , layer , socket ) when layer in [ "l" , "m" , "h" ] do
391
- if socket . assigns . layer == layer do
414
+ % { player: player } = socket . assigns
415
+
416
+ if player . layer == layer do
392
417
{ :noreply , socket }
393
418
else
394
419
PubSub . subscribe (
395
420
socket . assigns . player . pubsub ,
396
421
"streams:video:#{ socket . assigns . player . publisher_id } :#{ layer } "
397
422
)
398
423
399
- socket = assign ( socket , target_layer: layer )
424
+ player = % Player { player | target_layer: layer }
425
+
426
+ socket = assign ( socket , player: player )
400
427
broadcast_keyframe_req ( socket )
401
428
{ :noreply , socket }
402
429
end
@@ -431,7 +458,7 @@ defmodule LiveExWebRTC.Player do
431
458
defp broadcast_keyframe_req ( socket ) do
432
459
% { player: player } = socket . assigns
433
460
434
- layer = socket . assigns . target_layer || socket . assigns . layer
461
+ layer = player . target_layer || player . layer
435
462
436
463
PubSub . broadcast (
437
464
player . pubsub ,
@@ -440,6 +467,9 @@ defmodule LiveExWebRTC.Player do
440
467
)
441
468
end
442
469
470
+ defp keyframe? ( % RTPCodecParameters { mime_type: "video/H264" } , packet ) , do: H264 . keyframe? ( packet )
471
+ defp keyframe? ( % RTPCodecParameters { mime_type: "video/VP8" } , packet ) , do: VP8 . keyframe? ( packet )
472
+
443
473
defp flush_layer ( layer ) do
444
474
receive do
445
475
{ :live_ex_webrtc , :video , ^ layer , _packet } -> flush_layer ( layer )
0 commit comments