LiveExWebRTC.Publisher (live_ex_webrtc v0.8.0)
View SourceComponent for sending audio and video via WebRTC from a browser to a Phoenix app (browser publishes).
It:
- renders:
- audio and video device selects
- audio and video stream configs
- stream recording toggle (with recordings enabled)
- stream preview
- transmission stats
- on clicking "Start Streaming", creates WebRTC PeerConnection both on the client and server side
- connects those two peer connections negotiatiing a single audio and video track
- sends audio and video from selected devices to the live view process
- publishes received audio and video packets to the configured PubSub
- can optionally use the ExWebRTC Recorder to record the stream
When LiveExWebRTC.Player
is used, audio and video packets are delivered automatically,
assuming both components are configured with the same PubSub.
If LiveExWebRTC.Player
is not used, you should use following topics and messages:
streams:audio:#{publisher_id}:#{audio_track_id}
- for receiving audio packetsstreams:video:#{publisher_id}:#{video_track_id}:#{layer}
- for receiving video packets. The message is in form of{:live_ex_webrtc, :video, "l" | "m" | "h", ExRTP.Packet.t()}
or{:live_ex_webrtc, :audio, ExRTP.Packet.t()}
. Packets for non-simulcast video tracks are always sent with "h" identifier.streams:info:#{publisher.id}"
- for receiving information about publisher tracks and their layers. The message is in form of:{:live_ex_webrtc, :info | :bye, audio_track :: ExWebRTC.MediaStreamTrack.t(), video_track :: ExWebRTC.MediaStreamTrack.t()}
.publishers:#{publisher_id}
for sending keyframe request. The message must be in form of{:live_ex_webrtc, :keyframe_req, "l" | "m" | "h"}
E.g.PubSub.broadcast(LiveTwitch.PubSub, "publishers:my_publisher", {:live_ex_webrtc, :keyframe_req, "h"})
JavaScript Hook
Publisher live view requires JavaScript hook to be registered under Publisher
name.
The hook can be created using createPublisherHook
function.
For example:
import { createPublisherHook } from "live_ex_webrtc";
let Hooks = {};
const iceServers = [{ urls: "stun:stun.l.google.com:19302" }];
Hooks.Publisher = createPublisherHook(iceServers);
let liveSocket = new LiveSocket("/live", Socket, {
// ...
hooks: Hooks
});
Simulcast
Simulcast requires video codecs to be H264 (packetization mode 1) and/or VP8. E.g.
video_codecs = [
%RTPCodecParameters{
payload_type: 98,
mime_type: "video/H264",
clock_rate: 90_000,
sdp_fmtp_line: %FMTP{
pt: 98,
level_asymmetry_allowed: true,
packetization_mode: 1,
profile_level_id: 0x42E01F
}
},
%RTPCodecParameters{
payload_type: 96,
mime_type: "video/VP8",
clock_rate: 90_000
}
]
You can also use the shorthands for default H264 and VP8 codec parameters:
video_codecs = [:h264, :vp8]
Examples
defmodule LiveTwitchWeb.StreamerLive do
use LiveTwitchWeb, :live_view
alias LiveExWebRTC.Publisher
@impl true
def render(assigns) do
~H"""
<Publisher.live_render socket={@socket} publisher={@publisher} />
"""
end
@impl true
def mount(_params, _session, socket) do
socket = Publisher.attach(socket, id: "publisher", pubsub: LiveTwitch.PubSub)
{:ok, socket}
end
end
Summary
Types
Called when WebRTC has connected.
Called when WebRTC has disconnected.
Called when recorder sends a message to the Publisher.
Called when recorder finishes stream recording.
Types
Called when WebRTC has connected.
Called when WebRTC has disconnected.
@type on_packet() :: (publisher_id :: String.t(), packet_type :: :audio | :video, layer :: nil | String.t(), packet :: ExRTP.Packet.t(), socket :: Phoenix.LiveView.Socket.t() -> packet :: ExRTP.Packet.t())
@type on_recorder_message() :: (publisher_id :: String.t(), ExWebRTC.Recorder.message() -> any())
Called when recorder sends a message to the Publisher.
For exact meaning of the second argument, refer to ExWebRTC.Recorder.message/0
.
@type on_recording_finished() :: (publisher_id :: String.t(), ExWebRTC.Recorder.end_tracks_ok_result() -> any())
Called when recorder finishes stream recording.
For exact meaning of the second argument, refer to ExWebRTC.Recorder.end_tracks_ok_result/0
.
@type t() :: struct()
Functions
@spec attach(Phoenix.LiveView.Socket.t(), Keyword.t()) :: Phoenix.LiveView.Socket.t()
Attaches required hooks and creates t/0
struct.
Created struct is saved in socket's assigns and has to be passed to LiveExWebRTC.Publisher.live_render/1
.
Options:
id
[required] - publisher id. This is typically your user id (if there is users database). It is used to identify live view and generated HTML elements.pubsub
[required] - a pubsub that publisher live view will use for broadcasting audio and video packets received from a browser. See module doc for more info.recordings?
- whether to allow for recordings or not. Defaults to true. See module doc andon_disconnected/0
for more info.recorder_opts
- a list of options that will be passed to the recorder. In particular, they can contain S3 config where recordings will be uploaded. SeeExWebRTC.Recorder.option/0
for more.on_connected
- callback called when the underlying peer connection changes its state to the:connected
. Seeon_connected/0
.on_disconnected
- callback called when the underlying peer connection process terminates. Seeon_disconnected/0
.on_recording_finished
- callback called when the stream recording has finised. Seeon_recording_finished/0
.on_packet
- callback called for each audio and video RTP packet. Can be used to modify the packet before publishing it on a pubsub. Seeon_packet/0
.ice_servers
- a list ofExWebRTC.PeerConnection.Configuration.ice_server/0
,ice_ip_filter
-ExICE.ICEAgent.ip_filter/0
,ice_port_range
-Enumerable.t(non_neg_integer())/1
,audio_codecs
- a list ofExWebRTC.RTPCodecParameters.t/0
,video_codecs
- a list ofExWebRTC.RTPCodecParameters.t/0
,pc_genserver_opts
-GenServer.options/0
for the underlyingExWebRTC.PeerConnection
process.
Helper function for rendering Publisher live view.
Attributes
socket
(Phoenix.LiveView.Socket
) (required) - Parent live view socket.publisher
(LiveExWebRTC.Publisher
) (required) - Publisher struct. It is used to pass publisher id to the newly created live view via live view session. This data is then used to do a handshake between parent live view and child live view during which child live view receives the whole Publisher struct.