### start(pc_opts \\ [], gen_server_opts \\ []) Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.PeerConnection.html Starts a new `ExWebRTC.PeerConnection` process. ```APIDOC ## start(pc_opts \\ [], gen_server_opts \\ []) ### Description Starts a new `ExWebRTC.PeerConnection` process. ### Parameters - **pc_opts** (keyword()) - Optional - Options for the PeerConnection. - **gen_server_opts** (keyword()) - Optional - Options for the GenServer. ### Returns - `{:ok, pid}` on success, `{:error, reason}` on failure. ``` -------------------------------- ### start(recorder_opts \\ [], gen_server_opts \\ []) Source: https://hexdocs.pm/ex_webrtc_recorder/ExWebRTC.Recorder.html Starts a new ExWebRTC.Recorder process. ```APIDOC ## start(recorder_opts \\ [], gen_server_opts \\ []) ### Description Starts a new `ExWebRTC.Recorder` process. ### Method Function ### Signature `start(recorder_opts \\ [], gen_server_opts \\ [])` ### Parameters - **recorder_opts** (list) - Optional - Options for the recorder. See `options/0`. - **gen_server_opts** (list) - Optional - Options for the GenServer. ### Returns - `{:ok, pid}` - Success. ``` -------------------------------- ### start(pc_opts \\ [], gen_server_opts \\ []) Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.PeerConnection.html Starts a new PeerConnection process with optional configuration and GenServer options. ```APIDOC ## start(pc_opts \\ [], gen_server_opts \\ []) ### Description Starts a new `ExWebRTC.PeerConnection` process. It is a `GenServer` under the hood, so generic `GenServer.options/0` can be passed. ### Method start ### Parameters - **pc_opts** (ExWebRTC.PeerConnection.Configuration.options()) - Optional - Options for the PeerConnection configuration. - **gen_server_opts** (GenServer.options()) - Optional - Options for the GenServer. ### Returns - `GenServer.on_start()` - The result of starting the GenServer. ### Example ```elixir {:ok, pc} = ExWebRTC.PeerConnection.start() ``` ``` -------------------------------- ### start_link(recorder_opts \\ [], gen_server_opts \\ []) Source: https://hexdocs.pm/ex_webrtc_recorder/ExWebRTC.Recorder.html Starts a new ExWebRTC.Recorder process. ```APIDOC ## start_link(recorder_opts \\ [], gen_server_opts \\ []) ### Description Starts a new `ExWebRTC.Recorder` process. ### Method Function ### Signature `start_link(recorder_opts \\ [], gen_server_opts \\ [])` ### Parameters - **recorder_opts** (list) - Optional - Options for the recorder. See `options/0`. - **gen_server_opts** (list) - Optional - Options for the GenServer. ### Returns - `{:ok, pid}` - Success. ``` -------------------------------- ### Start ExWebRTC.PeerConnection process Source: https://hexdocs.pm/ex_webrtc/negotiation.html Starts an ExWebRTC.PeerConnection process, similar to creating an RTCPeerConnection in JavaScript. The ice_servers option is explained at the end of the tutorial. ```elixir # PeerConnection in Elixir WebRTC is a process! # take a look at the very end of the tutorial to learn what `ice_servers` option is {:ok, pc} = ExWebRTC.PeerConnection.start_link(ice_servers: [%{urls: "stun:stun.l.google.com:19302"}]) ``` -------------------------------- ### start_link(pc_opts \\ [], gen_server_opts \\ []) Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.PeerConnection.html Starts a new `ExWebRTC.PeerConnection` process linked to the caller. ```APIDOC ## start_link(pc_opts \\ [], gen_server_opts \\ []) ### Description Starts a new `ExWebRTC.PeerConnection` process linked to the caller. ### Parameters - **pc_opts** (keyword()) - Optional - Options for the PeerConnection. - **gen_server_opts** (keyword()) - Optional - Options for the GenServer. ### Returns - `{:ok, pid}` on success, `{:error, reason}` on failure. ``` -------------------------------- ### start_link(pc_opts \\ [], gen_server_opts \\ []) Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.PeerConnection.html Starts a new PeerConnection process linked to the caller. ```APIDOC ## start_link(pc_opts \\ [], gen_server_opts \\ []) ### Description Starts a new `ExWebRTC.PeerConnection` process. Works identically to `start/2`, but links to the calling process. ### Method start_link ### Parameters - **pc_opts** (ExWebRTC.PeerConnection.Configuration.options()) - Optional - Options for the PeerConnection configuration. - **gen_server_opts** (GenServer.options()) - Optional - Options for the GenServer. ### Returns - `GenServer.on_start()` - The result of starting the GenServer. ### Example ```elixir {:ok, pc} = ExWebRTC.PeerConnection.start_link() ``` ``` -------------------------------- ### Initialize Forwarder GenServer with PeerConnection and tracks Source: https://hexdocs.pm/ex_webrtc/forwarding.html Initializes the Forwarder GenServer by creating a PeerConnection with a STUN server, adding audio and video tracks to send back to the browser, and setting up maps for incoming and outgoing tracks. The in_tracks map starts empty because remote tracks arrive later as messages. ```elixir def init(_) do {:ok, pc} = PeerConnection.start_link(ice_servers: [%{urls: "stun:stun.l.google.com:19302"}]) # we expect to receive two tracks from the web browser - audio and video # so we also need to add two tracks here, we will use them to loop media back to the other browser # from each of the web browser tracks stream_id = MediaStreamTrack.generate_stream_id() audio_track = MediaStreamTrack.new(:audio, [stream_id]) video_track = MediaStreamTrack.new(:video, [stream_id]) {:ok, _sender} = PeerConnection.add_track(pc, audio_track) {:ok, _sender} = PeerConnection.add_track(pc, video_track) # in_tracks (tracks we will receive from the browser) = %{id => kind} # out_tracks (tracks we will send to the browser) = %{kind => id} in_tracks = %{} out_tracks = %{audio: audio_track.id, video: video_track.id} {:ok, %{pc: pc, out_tracks: out_tracks, in_tracks: in_tracks}} end ``` -------------------------------- ### Install and configure ExWebRTCDashboard Source: https://hexdocs.pm/ex_webrtc_dashboard/index.html Add the dependency and register the dashboard page. The first block adds the package to your mix dependencies. The second block configures the LiveDashboard route with the additional page. Both are required for the dashboard to appear. ```elixir def deps do [ {:ex_webrtc_dashboard, "~> 0.10.0"} ] end ``` ```elixir live_dashboard "/dashboard", additional_pages: [exwebrtc: ExWebRTCDashboard] ``` -------------------------------- ### Set sender codec with get_transceivers/1 Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.PeerConnection.html Example showing how to check available codecs via get_transceivers/1 and set the sender codec, preferring H264 over VP8. Can only be called once the first negotiation passes. ```elixir {:ok, pc} = PeerConnection.start_link() {:ok, rtp_sender} = PeerConnection.add_track(MediaStreamTrack.new(:video)) # exchange SDP with the remote side # {:ok, offer} = PeerConnection.create_offer(pc) # ... tr = pc |> PeerConnection.get_transceivers() |> Enum.find(fn tr -> tr.sender.id == rtp_sender.id end) dbg(tr.codecs) # list of supported codecs both for sending and receiving # e.g. always prefer h264 over vp8 h264 = Enum.find(tr.codecs, fn codec -> codec.mime_type == "video/H264" end) vp8 = Enum.find(tr.codecs, fn codec -> codec.mime_type == "video/VP8" end) :ok = PeerConnection.set_sender_codec(pc, rtp_sender.id, h264 || vp8) ``` -------------------------------- ### child_spec(init_arg) Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.PeerConnection.html Returns a specification to start this module under a supervisor. ```APIDOC ## child_spec(init_arg) ### Description Returns a specification to start this module under a supervisor. ### Method child_spec ### Parameters - **init_arg** - Required - The argument passed to the child specification. ### Returns - A supervisor child specification. ``` -------------------------------- ### child_spec(init_arg) Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.PeerConnection.html Returns a specification to start this module under a supervisor. ```APIDOC ## child_spec(init_arg) ### Description Returns a specification to start this module under a supervisor. ### Parameters - **init_arg** (term()) - Required - The argument passed to the child specification. ### Returns - A child specification. ``` -------------------------------- ### GenServer usage example for Munger with Simulcast layers Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.RTP.Munger.html Shows how to use Munger in a GenServer to handle RTP packets from a selected layer and switch layers. The example assumes two layers 'h' and 'l', and uses Munger.new(:h264, 90_000) and Munger.munge/2. ```elixir # assume you receive two layers: "h" (high) and "l" (low) # and this is a GenServer def init() do {:ok, %{munger: Munger.new(:h264, 90_000), layer: "h"}} end def handle_info({:ex_webrtc, _from, {:rtp, _id, rid, packet}}, state) do if rid == state.layer do {packet, munger} = Munger.munge(state.munger, packet) send_packet_somewhere(packet) {:noreply, %{state | munger: munger}} else {:noreply, state} end end def handle_info({:change_layer, layer}, state) do # indicate to the munger that the next packet will be from a new layer munger = Munger.update(state.munger) {:noreply, %{munger: munger, layer: layer} end ``` -------------------------------- ### start/2 type spec Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.PeerConnection.html Specifies the type signature for starting a new PeerConnection process. Accepts configuration options and GenServer options, returning a GenServer.on_start() result. ```elixir @spec start(ExWebRTC.PeerConnection.Configuration.options(), GenServer.options()) :: GenServer.on_start() ``` -------------------------------- ### Configure STUN server and IP filter in Elixir Source: https://hexdocs.pm/ex_webrtc/fly.html Starts a PeerConnection with a custom IP filter and STUN server configuration, using values from the application environment. ```elixir ip_filter = Application.get_env(:your_app, :ice_ip_filter) {:ok, pc} = PeerConnection.start_link( ice_ip_filter: ip_filter, ice_servers: [%{urls: "stun:stun.l.google.com:19302"}] ) ``` -------------------------------- ### start_link/2 type spec Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.PeerConnection.html Specifies the type signature for starting a new PeerConnection process linked to the caller. Accepts configuration options and GenServer options, returning a GenServer.on_start() result. ```elixir @spec start_link(ExWebRTC.PeerConnection.Configuration.options(), GenServer.options()) :: GenServer.on_start() ``` -------------------------------- ### Configure Simulcast layers in browser with sendEncodings Source: https://hexdocs.pm/ex_webrtc/debugging.html Use this JavaScript snippet to configure Simulcast layers in a browser. It sets three encodings with different resolutions and bitrates, and is referenced as an example from libwebrtc for choosing appropriate values. ```javascript mediaConstraints = {video: {width: { ideal: 1280 }, height: { ideal: 720 } }, audio: true}; const localStream = await navigator.mediaDevices.getUserMedia(mediaConstraints); const pc = new RTCPeerConnection(); pc.addTransceivers(localStream.getVideoTracks()[0], { sendEncodings: [ { rid: "h", maxBitrate: 1200 * 1024}, { rid: "m", scaleResolutionDownBy: 2, maxBitrate: 600 * 1024}, { rid: "l", scaleResolutionDownBy: 4, maxBitrate: 300 * 1024 }, ], }); ``` -------------------------------- ### Enable simulcast with addTransceiver and sendEncodings Source: https://hexdocs.pm/ex_webrtc/simulcast.html Enables simulcast when adding a video track to an RTCPeerConnection. Defines three encodings with rids 'h', 'm', and 'l', with scaleResolutionDownBy and maxBitrate settings. Requires a minimum starting resolution of 960x540 for three encodings. ```javascript const pc = new RTCPeerConnection(); const localStream = await navigator.mediaDevices.getUserMedia({ video: { width: { ideal: 1280 }, height: { ideal: 720 }, }, }); pc.addTransceiver(localStream.getVideoTracks()[0], { streams: [localStream], sendEncodings: [ { rid: 'h', maxBitrate: 1500 * 1024 }, { rid: 'm', scaleResolutionDownBy: 2, maxBitrate: 600 * 1024 }, { rid: 'l', scaleResolutionDownBy: 4, maxBitrate: 300 * 1024 }, ], }); ``` -------------------------------- ### Offer to receive data: set transceiver direction to sendonly Source: https://hexdocs.pm/ex_webrtc/mastering_transceivers.html Use when offering to receive media tracks: set the remote transceiver direction to sendonly after receiving the offer, otherwise the track becomes inactive. The JavaScript example uses RTCPeerConnection and the Elixir example uses PeerConnection module functions. ```JavaScript pc1 = new RTCPeerConnection(); pc2 = new RTCPeerConnection(); tr = pc1.addTransceiver("audio", { direction: "recvonly" }); offer = await pc1.createOffer(); await pc1.setLocalDescription(offer); await pc2.setRemoteDescription(offer); // change direction from default "recvonly" to "sendonly" // in other case, when negotiation finishes, // currentDirection of this transceiver will be inactive pc2.getTransceivers()[0].direction = "sendonly"; answer = await pc2.createAnswer(); await pc2.setLocalDescription(answer); await pc1.setRemoteDescription(answer); console.log(pc2.getTransceivers()[0].direction); console.log(pc2.getTransceivers()[0].currentDirection); ``` ```Elixir {:ok, pc1} = PeerConnection.start_link() {:ok, pc2} = PeerConnection.start_link() {:ok, _tr} = PeerConnection.add_transceiver(pc1, :audio, direction: :recvonly) {:ok, offer} = PeerConnection.create_offer(pc1) :ok = PeerConnection.set_local_description(pc1, offer) :ok = PeerConnection.set_remote_description(pc2, offer) [pc2_tr] = PeerConnection.get_transceivers(pc2) :ok = PeerConnection.set_transceiver_direction(pc2, pc2_tr.id, :sendonly) {:ok, answer} = PeerConnection.create_answer(pc2) :ok = PeerConnection.set_local_description(pc2, answer) :ok = PeerConnection.set_remote_description(pc1, answer) [pc2_tr] = PeerConnection.get_transceivers(pc2) IO.inspect(pc2_tr.direction) IO.inspect(pc2_tr.current_direction) ``` -------------------------------- ### create_offer(peer_connection, options \\ []) Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.PeerConnection.html Creates an SDP offer for the PeerConnection. Returns the offer as a SessionDescription. ```APIDOC ## create_offer(peer_connection, options \\ []) ### Description Creates an SDP offer. For more information, refer to the RTCPeerConnection: createOffer() method. ### Method create_offer ### Endpoint create_offer(peer_connection, options \\ []) ### Parameters #### Path Parameters - **peer_connection** (peer_connection()) - Required - The PeerConnection process. - **options** (list of tuples) - Optional - Options for the offer, e.g., `{:ice_restart, boolean()}`. ### Response #### Success Response - **{:ok, ExWebRTC.SessionDescription.t()}** (tuple) - Returned when the offer is created successfully. #### Error Response - **{:error, term()}** (tuple) - Returned when the operation fails. #### Response Example ``` {:ok, %ExWebRTC.SessionDescription{}} ``` ``` -------------------------------- ### create_offer(peer_connection, options \\ []) Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.PeerConnection.html Creates an SDP offer. ```APIDOC ## create_offer(peer_connection, options \\ []) ### Description Creates an SDP offer. ### Parameters - **peer_connection** (peer_connection()) - Required - The PeerConnection process. - **options** (keyword()) - Optional - Options for the offer. ### Returns - `{:ok, description}` on success, `{:error, reason}` on failure. ``` -------------------------------- ### Add ex_webrtc dependency in mix.exs Source: https://hexdocs.pm/ex_webrtc/readme.html Adds the ex_webrtc dependency to a Mix project. Use this in the deps function of mix.exs to install the library. ```elixir def deps do [ {:ex_webrtc, "~> 0.17.0"} ] end ``` -------------------------------- ### Configure STUN server in PeerConnection.start_link Source: https://hexdocs.pm/ex_webrtc/bare.html Configure a STUN server for NAT traversal when deploying behind a NAT. Uses Google's public STUN server; note that relying on external infrastructure means you depend on its availability. ```elixir PeerConnection.start_link(ice_servers: [%{urls: "stun:stun.l.google.com:19302"}]) ``` -------------------------------- ### option() type definition Source: https://hexdocs.pm/ex_webrtc_recorder/ExWebRTC.Recorder.html Defines the options that can be passed to start_link/1. Includes :base_dir, :on_start, :controlling_process, and :s3_upload_config. ```elixir @type option() :: {:base_dir, String.t()} | {:on_start, (-> [ExWebRTC.MediaStreamTrack.t()])} | {:controlling_process, Process.dest()} | {:s3_upload_config, ExWebRTC.Recorder.S3.upload_config()} ``` -------------------------------- ### Get user media with getUserMedia Source: https://hexdocs.pm/ex_webrtc/negotiation.html Obtains media tracks from the webcam and microphone using the mediaDevices JavaScript API. A permission popup appears after calling this function. ```javascript // a popup asking for permissions should appear after calling this function const localStream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true }); ``` -------------------------------- ### Decode VP8 video and run machine learning model Source: https://hexdocs.pm/ex_webrtc/consuming.html Initialize a depayloader, decoder, and serving in init/1. In handle_info/2, depayload the RTP packet, decode the frame, convert to Nx tensor, and run the model. Handle errors and update state. ```elixir def init(_) do # ... serving = # setup your machine learning model (i.e. using Bumblebee) state = %{ depayloader: ExWebRTC.Media.VP8.Depayloader.new(), decoder: Xav.Decoder.new(:vp8), serving: serving } {:ok, state} end def handle_info({:ex_webrtc, _from, {:rtp, _track_id, nil, packet}}, state) do depayloader = with {:ok, frame, depayloader} <- ExWebRTC.RTP.VP8.Depayloader.write(state.depayloader, packet), {:ok, raw_frame} <- Xav.Decoder.decode(state.decoder, frame) do # raw frame is just a 3D matrix with the shape of resolution x colors (e.g 1920 x 1080 x 3 for FullHD, RGB frame) # we can cast it to Elixir Nx tensor and use it as the machine learning model input # machine learning stuff is out of scope of this tutorial, but you probably want to check out Elixir Nx and friends tensor = Xav.Frame.to_nx(raw_frame) prediction = Nx.Serving.run(state.serving, tensor) # do something with the prediction depayloader else {:ok, depayloader} -> depayloader {:error, _err} -> # handle the error end {:noreply, %{state | depayloader: depayloader}} end ``` -------------------------------- ### Configure VP8 codec in PeerConnection.start_link Source: https://hexdocs.pm/ex_webrtc/consuming.html Use this snippet to force a specific codec (VP8) in the PeerConnection configuration. This simplifies depayloading but may fail negotiation if the other peer does not support the codec. ```elixir codec = %ExWebRTC.RTPCodecParameters{ payload_type: 96, mime_type: "video/VP8", clock_rate: 90_000 } {:ok, pc} = ExWebRTC.PeerConnection.start_link(video_codecs: [codec]) ``` -------------------------------- ### Send offer via WebSocket Source: https://hexdocs.pm/ex_webrtc/negotiation.html Serializes the offer to JSON and sends it to the Elixir app via a WebSocket relay service. The WebRTC standard does not specify how to exchange offers, so this is just an example. ```javascript const json = JSON.stringify(offer); webSocket.send_offer(json); ``` -------------------------------- ### open(path, opts \ []) Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.Media.Ogg.Writer.html Opens a new Ogg writer. The writer must be closed with close/1 to ensure all data is written. ```APIDOC ## open(path, opts \\ []) ### Description Opens a new Ogg writer. The writer MUST be closed with close/1, otherwise some of the data might not be written to a file. ### Function Signature ```elixir @spec open(Path.t(), sample_rate: non_neg_integer(), channel_count: non_neg_integer()) :: {:ok, t()} | {:error, term()} ``` ### Parameters - **path** (Path.t()) - Required - The file path where the Ogg file will be written. - **opts** (keyword) - Optional - Options: - **sample_rate** (non_neg_integer()) - Required - The sample rate of the Opus stream. - **channel_count** (non_neg_integer()) - Required - The number of channels in the Opus stream. ### Returns - `{:ok, t()}` - The writer handle on success. - `{:error, term()}` - An error tuple on failure. ### Example ```elixir {:ok, writer} = ExWebRTC.Media.Ogg.Writer.open("output.ogg", sample_rate: 48000, channel_count: 2) ``` ``` -------------------------------- ### open(path, list) Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.Media.IVF.Writer.html Creates a new IVF writer with the specified parameters. ```APIDOC ## open(path, list) ### Description Creates a new IVF writer. Initially, IVF header is written with `num_frames` and is updated every `num_frames` by `num_frames`. To have a precise number of frames in the header, either write exactly `num_frames` or call `close/1` at the end of writing. ### Method open ### Parameters - **path** (Path.t()) - Required - The file path to write the IVF file. - **fourcc** (non_neg_integer()) - Required - The FourCC codec identifier. - **height** (non_neg_integer()) - Required - The height of the video frames. - **width** (non_neg_integer()) - Required - The width of the video frames. - **num_frames** (pos_integer()) - Required - The number of frames to write. - **timebase_denum** (non_neg_integer()) - Required - The denominator of the timebase. - **timebase_num** (pos_integer()) - Required - The numerator of the timebase. ### Returns - `{:ok, t()}` or `{:error, term()}` ``` -------------------------------- ### Warmup: Establish WebRTC connection and replaceTrack Source: https://hexdocs.pm/ex_webrtc/mastering_transceivers.html Warmup technique: establish a WebRTC connection before media is available, then attach a MediaStreamTrack using replaceTrack. The JavaScript version uses navigator.mediaDevices.getUserMedia and tr.sender.replaceTrack. The Elixir version uses PeerConnection.replace_track for parity, noting that media is normally sent via send_rtp. ```JavaScript pc1 = new RTCPeerConnection(); pc2 = new RTCPeerConnection(); tr = pc1.addTransceiver("audio"); offer = await pc1.createOffer(); await pc1.setLocalDescription(offer); await pc2.setRemoteDescription(offer); answer = await pc2.createAnswer(); await pc2.setLocalDescription(answer); await pc1.setRemoteDescription(answer); // once MediaStreamTrack is ready, // start sending it with replaceTrack const localStream = await navigator.mediaDevices.getUserMedia({ audio: true, video: false}); await tr.sender.replaceTrack(localStream.getTracks()[0]); ``` ```Elixir {:ok, pc1} = PeerConnection.start_link() {:ok, pc2} = PeerConnection.start_link() {:ok, tr} = PeerConnection.add_transceiver(pc1, :audio) {:ok, offer} = PeerConnection.create_offer(pc1) :ok = PeerConnection.set_local_description(pc1, offer) :ok = PeerConnection.set_remote_description(pc2, offer) {:ok, answer} = PeerConnection.create_answer(pc2) :ok = PeerConnection.set_local_description(pc2, answer) :ok = PeerConnection.set_remote_description(pc1, answer) # although in Elixir WebRTC user has to send media on their own, # using send_rtp function, we also added replace_track function # for parity with JavaScript API track = MediaStreamTrack.new(:audio) :ok = PeerConnection.replace_track(pc1, tr.sender.id, track) ``` -------------------------------- ### Get remote tracks from transceivers Source: https://hexdocs.pm/ex_webrtc/forwarding.html Retrieves all remote tracks by iterating over the PeerConnection's transceivers. Use this to obtain the tracks that the remote peer has added, which are needed for handling incoming RTP packets. ```elixir tracks = peer_connection |> PeerConnection.get_transceivers() |> Enum.map(&(&1.receiver.track)) ``` -------------------------------- ### Register ExWebRTCDashboard as LiveDashboard page Source: https://hexdocs.pm/ex_webrtc_dashboard/readme.html Add ExWebRTCDashboard as an additional page in your live_dashboard configuration. This enables automatic discovery of peer connections. ```elixir live_dashboard "/dashboard", additional_pages: [exwebrtc: ExWebRTCDashboard] ``` -------------------------------- ### Add ex_webrtc dependency in mix.exs Source: https://hexdocs.pm/ex_webrtc/index.html Add the ex_webrtc dependency to mix.exs. The second snippet also adds the optional ex_sctp dependency to enable DataChannels support; note that ex_sctp requires Rust to be installed. ```elixir def deps do [ {:ex_webrtc, "~> 0.17.0"} ] end ``` ```elixir def deps do [ {:ex_webrtc, "~> 0.17.0"}, {:ex_sctp, "~> 0.1.2"} ] end ``` -------------------------------- ### t() Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.PeerConnection.Configuration.html The configuration struct for ExWebRTC.PeerConnection. It is created from options passed to `ExWebRTC.PeerConnection.start_link/1`. ```APIDOC ## t() ### Description `ExWebRTC.PeerConnection` configuration. It is created from options passed to `ExWebRTC.PeerConnection.start_link/1`. See `options/0` for more. ### Type Definition ``` @type t() :: %ExWebRTC.PeerConnection.Configuration{ audio_codecs: [ExWebRTC.RTPCodecParameters.t()], audio_extensions: [ExSDP.Attribute.Extmap.t()], controlling_process: Process.dest(), features: [feature()], host_to_srflx_ip_mapper: ExICE.ICEAgent.host_to_srflx_ip_mapper() | nil, ice_aggressive_nomination: boolean(), ice_ip_filter: (:inet.ip_address() -> boolean()) | nil, ice_port_range: Enumerable.t(non_neg_integer()), ice_servers: [ice_server()], ice_transport_policy: :relay | :all, ice_transport_protocol: :udp | :tcp, logger_metadata: Enumerable.t({atom(), term()}), video_codecs: [ExWebRTC.RTPCodecParameters.t()], video_extensions: [ExSDP.Attribute.Extmap.t()] } ``` ### Fields - **audio_codecs** (list of ExWebRTC.RTPCodecParameters.t()) - Required - List of audio codecs. - **audio_extensions** (list of ExSDP.Attribute.Extmap.t()) - Required - List of audio RTP header extensions. - **controlling_process** (Process.dest()) - Required - The process that controls the PeerConnection. - **features** (list of feature()) - Required - List of enabled features. - **host_to_srflx_ip_mapper** (function or nil) - Optional - Function to map host IPs to srflx IPs. - **ice_aggressive_nomination** (boolean) - Required - Whether aggressive nomination is used. - **ice_ip_filter** (function or nil) - Optional - Function to filter ICE IP addresses. - **ice_port_range** (Enumerable of non_neg_integer) - Required - Range of ports for ICE. - **ice_servers** (list of ice_server()) - Required - List of ICE servers. - **ice_transport_policy** (:relay or :all) - Required - ICE transport policy. - **ice_transport_protocol** (:udp or :tcp) - Required - ICE transport protocol. - **logger_metadata** (Enumerable of {atom, term}) - Required - Metadata for logging. - **video_codecs** (list of ExWebRTC.RTPCodecParameters.t()) - Required - List of video codecs. - **video_extensions** (list of ExSDP.Attribute.Extmap.t()) - Required - List of video RTP header extensions. ``` -------------------------------- ### Configure STUN server in JavaScript Source: https://hexdocs.pm/ex_webrtc/fly.html Sets up an RTCPeerConnection with a STUN server (stun:stun.l.google.com:19302) for WebRTC on the client side. ```javascript pc = new RTCPeerConnection({ iceServers: [{ urls: "stun:stun.l.google.com:19302" }], }); ``` -------------------------------- ### Bidirectional connection with single negotiation (Warmup) in JavaScript and Elixir Source: https://hexdocs.pm/ex_webrtc/mastering_transceivers.html Establishes a bidirectional connection in a single negotiation using the Warmup technique. Applying the answer on pc1 triggers a `track` event. The JavaScript version changes the transceiver direction from the default "recvonly" to "sendrecv" before creating the answer; the Elixir version uses `PeerConnection.set_transceiver_direction/3` and waits for `{:ex_webrtc, ^pc2, {:track, _track}}` messages. ```JavaScript pc1 = new RTCPeerConnection(); pc2 = new RTCPeerConnection(); pc1.ontrack = ev => console.log("pc1 ontrack"); pc2.ontrack = ev => console.log("pc2 ontrack"); tr = pc1.addTransceiver("audio"); offer = await pc1.createOffer(); await pc1.setLocalDescription(offer); await pc2.setRemoteDescription(offer); // change direction from default "recvonly" to "sendrecv" pc2.getTransceivers()[0].direction = "sendrecv"; answer = await pc2.createAnswer(); await pc2.setLocalDescription(answer); await pc1.setRemoteDescription(answer); ``` ```Elixir {:ok, pc1} = PeerConnection.start_link() {:ok, pc2} = PeerConnection.start_link() {:ok, _tr} = PeerConnection.add_transceiver(pc1, :audio) {:ok, offer} = PeerConnection.create_offer(pc1) :ok = PeerConnection.set_local_description(pc1, offer) :ok = PeerConnection.set_remote_description(pc2, offer) receive do {:ex_webrtc, ^pc2, {:track, _track}} = msg -> IO.inspect(msg) end [pc2_tr] = PeerConnection.get_transceivers(pc2) :ok = PeerConnection.set_transceiver_direction(pc2, pc2_tr.id, :sendrecv) {:ok, answer} = PeerConnection.create_answer(pc2) :ok = PeerConnection.set_local_description(pc2, answer) :ok = PeerConnection.set_remote_description(pc1, answer) receive do {:ex_webrtc, ^pc1, {:track, _track}} = msg -> IO.inspect(msg) end ``` -------------------------------- ### Switch simulcast encodings with Munger and send_pli Source: https://hexdocs.pm/ex_webrtc/simulcast.html Steps to switch between simulcast encodings: create a munger with the codec sample rate, munge packets from the current encoding, and switch by sending a PLI and updating the munger when a keyframe arrives. The example shows transitioning from encoding 'm' to 'h'. ```elixir alias ExWebRTC.PeerConnection alias ExWebRTC.RTP.{H264, Munger} m = Munger.new(:h264, 90_000) ``` ```elixir receive do {:ex_webrtc, input_pc, {:rtp, _input_track_id, "m", packet}} -> {packet, munger} = Munger.munge(munger, packet) :ok = PeerConnection.send_rtp(output_pc, output_track_id, packet) {:ex_webrtc, input_pc, {:rtp, _input_track_id, _rid, packet}} -> # ignore other packets end ``` ```elixir # assume we have the following state state = %{ current_encoding: "m", munger: munger, input_pc: input_pc, input_track_id: input_track_id, output_pc: output_pc, output_track_id: output_track_id } :ok = PeerConnection.send_pli(state.input_pc, state.input_track_id, "h") # ... receive do {:ex_webrtc, input_pc, {:rtp, _input_track_id, rid, packet}} -> cond do rid == state.current_encoding -> {munger, packet} = Munger.munge(munger, packet) :ok = PeerConnection.send_rtp(state.output_pc, state.output_track_id, packet) %{state | munger: munger} rid == "h" and H264.keyframe?(packet) -> munger = Munger.update(munger) {munger, packet} = Munger.munge(munger, packet) :ok = PeerConnection.send_rtp(state.output_pc, state.output_track_id, packet) %{state | munger: munger, current_encoding: "h"} true -> state end end ``` -------------------------------- ### open(path) Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.Media.IVF.Reader.html Opens an IVF file and reads its header. ```APIDOC ## open(path) ### Description Opens an IVF file and reads its header. ### Parameters - **path** (Path.t()) - Required - The path to the IVF file. ### Returns - `{:ok, ExWebRTC.Media.IVF.Header.t(), t()}` - On success, returns the header and the reader. - `{:error, term()}` - On failure, returns an error. ``` -------------------------------- ### Add ex_webrtc_dashboard dependency Source: https://hexdocs.pm/ex_webrtc_dashboard/readme.html Add the ex_webrtc_dashboard package to your mix.exs dependencies. Version ~> 0.10.0 is specified. ```elixir def deps do [ {:ex_webrtc_dashboard, "~> 0.10.0"} ] end ``` -------------------------------- ### create_data_channel(peer_connection, label, opts \\ []) Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.PeerConnection.html Creates a new DataChannel with the given label and options. Returns the DataChannel on success. ```APIDOC ## create_data_channel(peer_connection, label, opts \\ []) ### Description Creates a new DataChannel. For more information, refer to the RTCPeerConnection: createDataChannel() method. ### Method create_data_channel ### Endpoint create_data_channel(peer_connection, label, opts \\ []) ### Parameters #### Path Parameters - **peer_connection** (peer_connection()) - Required - The PeerConnection process. - **label** (String.t()) - Required - The label for the DataChannel. - **opts** (ExWebRTC.DataChannel.options()) - Optional - Options for the DataChannel. ### Response #### Success Response - **{:ok, ExWebRTC.DataChannel.t()}** (tuple) - Returned when the DataChannel is created successfully. #### Error Response - **{:error, atom()}** (tuple) - Returned when the operation fails. #### Response Example ``` {:ok, %ExWebRTC.DataChannel{}} ``` ``` -------------------------------- ### new(type, rtp_mapping, fmtp, rtcp_fbs) Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.RTPCodecParameters.html Creates a new `ExWebRTC.RTPCodecParameters` struct from the given RTP mapping, FMTP attribute, and RTCP feedback attributes. ```APIDOC ## new(type, rtp_mapping, fmtp, rtcp_fbs) ### Description Creates a new `ExWebRTC.RTPCodecParameters` struct from the given RTP mapping, FMTP attribute, and RTCP feedback attributes. ### Parameters - **type** (`:audio | :video`) - Required - The media type of the codec. - **rtp_mapping** (`ExSDP.Attribute.RTPMapping.t()`) - Required - The RTP mapping attribute. - **fmtp** (`ExSDP.Attribute.FMTP.t() | nil`) - Required - The FMTP attribute, or `nil` if not present. - **rtcp_fbs** (`[ExSDP.Attribute.RTCPFeedback.t()]`) - Required - A list of RTCP feedback attributes. ### Returns - `ExWebRTC.RTPCodecParameters.t()` - The new codec parameters struct. ``` -------------------------------- ### new(codec_params) Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.RTP.Munger.html Creates a new `ExWebRTC.RTP.Munger.t/0`. ```APIDOC ## new(codec_params) ### Description Creates a new `ExWebRTC.RTP.Munger.t/0`. ### Signature ```elixir @spec new(:opus | :h264 | :vp8 | ExWebRTC.RTPCodecParameters.t(), non_neg_integer()) :: t() ``` ### Parameters - **codec_params** (atom or ExWebRTC.RTPCodecParameters.t()) - Required - The codec parameters or codec atom. - **clock_rate** (non_neg_integer()) - Required - The clock rate of the codec carried in munged RTP packets. ### Returns - **t()** - A new munger. ``` -------------------------------- ### open(path) Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.Media.Ogg.Reader.html Opens an Ogg file. Reads the ID and Comment Headers (ignored for now). Works only with a single Opus stream in the container. ```APIDOC ## open(path) ### Description Opens an Ogg file. For now, works only with single Opus stream in the container. This function reads the ID and Comment Headers (and, for now, ignores them). ### Function Signature ```elixir @spec open(Path.t()) :: {:ok, t()} | {:error, term()} ``` ### Parameters - **path** (Path.t()) - Required - The path to the Ogg file. ### Returns - `{:ok, t()}` - Returns an Ogg reader tuple on success. - `{:error, term()}` - Returns an error tuple on failure. ``` -------------------------------- ### create_answer(peer_connection) Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.PeerConnection.html Creates an SDP answer for the PeerConnection. Returns the answer as a SessionDescription. ```APIDOC ## create_answer(peer_connection) ### Description Creates an SDP answer. For more information, refer to the RTCPeerConnection: createAnswer() method. ### Method create_answer ### Endpoint create_answer(peer_connection) ### Parameters #### Path Parameters - **peer_connection** (peer_connection()) - Required - The PeerConnection process. ### Response #### Success Response - **{:ok, ExWebRTC.SessionDescription.t()}** (tuple) - Returned when the answer is created successfully. #### Error Response - **{:error, term()}** (tuple) - Returned when the operation fails. #### Response Example ``` {:ok, %ExWebRTC.SessionDescription{}} ``` ``` -------------------------------- ### create_answer(peer_connection) Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.PeerConnection.html Creates an SDP answer. ```APIDOC ## create_answer(peer_connection) ### Description Creates an SDP answer. ### Parameters - **peer_connection** (peer_connection()) - Required - The PeerConnection process. ### Returns - `{:ok, description}` on success, `{:error, reason}` on failure. ``` -------------------------------- ### Create and set WebRTC offer Source: https://hexdocs.pm/ex_webrtc/negotiation.html Creates and sets an offer on the RTCPeerConnection. The offer contains information about the tracks to send, codecs, and whether to receive media. The other side responds with an answer that can accept, reject, or partially accept the offer. ```javascript const offer = await pc.createOffer(); // offer == { type: "offer", sdp: ""} await pc.setLocalDescription(offer); ``` -------------------------------- ### Add ex_webrtc_recorder with S3 dependencies Source: https://hexdocs.pm/ex_webrtc_recorder/readme.html Adds ex_webrtc_recorder with optional S3 support dependencies. Requires ex_aws_s3, ex_aws, sweet_xml, and an HTTP client like hackney. See ExWebRTC.Recorder.S3 for more info. ```elixir def deps do [ {:ex_webrtc_recorder, "~> 0.4.0"}, {:ex_aws_s3, "~> 2.5"}, {:ex_aws, "~> 2.5"}, {:sweet_xml, "~> 0.7"}, {:hackney, "~> 1.9"} # or any other HTTP client supported by `ex_aws` ] end ``` -------------------------------- ### new(codec_params, opts \\ []) Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.RTP.Payloader.html Creates a new payloader that matches the passed codec parameters. Accepts an optional max_payload_size option. ```APIDOC ## new(codec_params, opts \\ []) ### Description Creates a new payloader that matches the passed codec parameters. ### Parameters - **codec_params** (ExWebRTC.RTPCodecParameters.t()) - Required - The codec parameters to match. - **opts** (list) - Optional - Options: - **max_payload_size** (integer()) - Optional - Maximum size of a single RTP packet. Must be greater than 100. Defaults to 1000. ### Returns - `{:ok, payloader()}` - Successfully created payloader. - `{:error, :no_payloader_for_codec}` - No payloader available for the given codec. ``` -------------------------------- ### Add ex_webrtc_recorder dependency Source: https://hexdocs.pm/ex_webrtc_recorder/readme.html Adds the ex_webrtc_recorder dependency to a Mix project. Required for basic recording functionality. ```elixir def deps do [ {:ex_webrtc_recorder, "~> 0.4.0"} ] end ``` -------------------------------- ### create_data_channel(peer_connection, label, opts \\ []) Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.PeerConnection.html Creates a new DataChannel. ```APIDOC ## create_data_channel(peer_connection, label, opts \\ []) ### Description Creates a new DataChannel. ### Parameters - **peer_connection** (peer_connection()) - Required - The PeerConnection process. - **label** (String.t()) - Required - The label of the DataChannel. - **opts** (keyword()) - Optional - Options for the DataChannel. ### Returns - `{:ok, channel}` on success, `{:error, reason}` on failure. ``` -------------------------------- ### get_all_running() Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.PeerConnection.html Returns a list of all running ExWebRTC.PeerConnection processes. ```APIDOC ## get_all_running() ### Description Returns a list of all running `ExWebRTC.PeerConnection` processes. ### Method Function ### Signature `@spec get_all_running() :: [pid()]` ### Parameters None ### Returns - **list of pid()** - List of all running `ExWebRTC.PeerConnection` processes. ``` -------------------------------- ### PeerConnection configuration type definition Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.PeerConnection.Configuration.html Defines the `ExWebRTC.PeerConnection.Configuration` struct. It is created from options passed to `ExWebRTC.PeerConnection.start_link/1`; see `options/0` for details. ```elixir @type t() :: %ExWebRTC.PeerConnection.Configuration{ audio_codecs: [ExWebRTC.RTPCodecParameters.t()], audio_extensions: [ExSDP.Attribute.Extmap.t()], controlling_process: Process.dest(), features: [feature()], host_to_srflx_ip_mapper: ExICE.ICEAgent.host_to_srflx_ip_mapper() | nil, ice_aggressive_nomination: boolean(), ice_ip_filter: (:inet.ip_address() -> boolean()) | nil, ice_port_range: Enumerable.t(non_neg_integer()), ice_servers: [ice_server()], ice_transport_policy: :relay | :all, ice_transport_protocol: :udp | :tcp, logger_metadata: Enumerable.t({atom(), term()}), video_codecs: [ExWebRTC.RTPCodecParameters.t()], video_extensions: [ExSDP.Attribute.Extmap.t()] } ``` -------------------------------- ### new(opts \\ []) Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.RTP.JitterBuffer.html Creates a new JitterBuffer instance with optional latency configuration. ```APIDOC ## new(opts \\ []) ### Description Creates a new `ExWebRTC.RTP.JitterBuffer.t/0`. ### Parameters - **opts** (options()) - Optional - Options that can be passed to `new/1`. See `options/0` for details. ### Returns - **buffer** (t()) - A new JitterBuffer instance. ### Example ```elixir jitter_buffer = ExWebRTC.RTP.JitterBuffer.new() ``` ``` -------------------------------- ### get_all_running() Source: https://hexdocs.pm/ex_webrtc/ExWebRTC.PeerConnection.html Returns a list of all running `ExWebRTC.PeerConnection` processes. ```APIDOC ## get_all_running() ### Description Returns a list of all running `ExWebRTC.PeerConnection` processes. ### Parameters None. ### Returns - A list of `peer_connection()`. ``` -------------------------------- ### Negotiate only one codec with ExWebRTC Source: https://hexdocs.pm/ex_webrtc/modifying.html Negotiates only the VP8 codec by passing a single codec parameter to `PeerConnection.start_link/1`. Use this when you want to avoid codec mismatch by limiting the negotiation to one codec. ```elixir codec = %ExWebRTC.RTPCodecParameters{ payload_type: 96, mime_type: "video/VP8", clock_rate: 90_000 } {:ok, pc} = PeerConnection.start_link(video_codecs: [codec]) ``` -------------------------------- ### Handle SDP offer in Elixir Source: https://hexdocs.pm/ex_webrtc/negotiation.html Handles an SDP offer received from the web browser via WebSocket. Decodes the JSON message using the Jason library, converts it to an ExWebRTC.SessionDescription, and sets it as the remote description on the PeerConnection. ```elixir # we will use the Jason library for decoding the JSON message receive do {:web_socket, {:offer, json}} -> offer = json |> Jason.decode!() |> ExWebRTC.SessionDescription.from_json() ExWebRTC.PeerConnection.set_remote_description(pc, offer) end ```