MatijaL

MatijaL

Got stuck integrating PeerJS (WebRTC) with my LiveView app

Hi guys,

I’m trying to integrate PeerJS to my Phoenix LiveView App. So, I want to support video calling between users using WebRTC. This is a learning project and I have never done anything like this, there are many new concepts here that I don’t fully understand so naturally, I got stuck.

So, first a user creates a talk, then a show template is rendered where videos should show. Video from a user shows fine, but I’m not sure how to connect it to another user inside a talk.

Can anyone help?

show.ex

defmodule MyAppWeb.TalkLive.Show do
  use MyAppWeb, :live_view

  alias MyApp.Accounts
  alias MyApp.Profiles
  alias MyApp.Talks
  alias MyAppWeb.Presence
  alias Phoenix.Socket.Broadcast

  @impl true
  def mount(%{"slug" => slug}, %{"user_token" => user_token} = _session, socket) do
    current_user = Accounts.get_user_by_session_token(user_token)
    profile = Profiles.get_profile!(current_user.id)

    if connected?(socket) do
      Phoenix.PubSub.subscribe(MyApp.PubSub, "talk:" <> slug)
      Phoenix.PubSub.subscribe(MyApp.PubSub, "talk:" <> slug <> ":" <> to_string(current_user.id))

      {:ok, _} = Presence.track_talk_user(self(), "talk:" <> slug, current_user, profile)
    end

    case Talks.get_talk(slug) do
      nil ->
        {:ok,
          socket
          |> assign(:current_user, current_user)
          |> assign(:profile, profile)
          |> put_flash(:error, "That Talk does not exist.")
          |> push_navigate(to: ~p"/talks/new")
        }
      talk ->
        {:ok,
          socket
          |> assign(:current_user, current_user)
          |> assign(:profile, profile)
          |> assign(:talk, talk)
          |> assign(:online_users, list_online_users(talk))
        }
    end
  end

  @impl true
  def handle_info(%Broadcast{event: "presence_diff"}, socket) do
    talk = socket.assigns.talk

    {:noreply,
      socket
      |> assign(:online_users, list_online_users(talk))}
  end

  defp list_online_users(talk) do
    Presence.list("talk:" <> talk.slug)
    |> Enum.map(fn {_k, %{metas: [v]}} -> v end)
  end
end

show.html.heex

<div class="flex">
  <div id="video-grid" class="">
    <video id="local-video" class="rotate-video" playsinline autoplay muted class="w-1/2 bg-red-800"></video>
    <div class=""><%= @profile.username %></div>
  </div>

  <%= for user <- @online_users do %>
    <%= unless user.user_id == @current_user.id do %>
      <div class="">
        <video id={"remote-video-#{user.user_id}"} data-user-id={user.user_id} playsinline autoplay class="w-96 bg-green-800"></video>
        <div class=""><%= user.username %></div>
      </div>
    <% end %>
  <% end %>
</div>

<.button id="join-call" phx-hook="JoinCall" data-user-id={@current_user.id}>Join Call</.button>

app.js

let Hooks = {}

Hooks.JoinCall = {
  mounted() {
    console.log("Connected to Call")

    const currentUserId = "bljeeee-" + this.el.dataset.userId
    console.log(this.el.dataset)
    console.log("Current User ID: ", currentUserId)

    const videoGrid = document.getElementById("video-grid")
    const localVideo = document.getElementById("local-video")
    const remoteVideo = document.getElementById("remote-video")

    async function initStream() {
      try {
        var peer = new Peer();

        peer.on("open", id => {
          console.log("Peer ID: ", id)
        })
        

        navigator.mediaDevices.getUserMedia({audio: true, video: true}).then(stream => {
          addVideoStream(localVideo, stream)
        })

      } catch (e) {
        console.log("JoinCall ERROR")
        console.log(e)
      }
    }

    this.el.addEventListener("click", e => {
      initStream()
    })

    function addVideoStream(video, stream) {
      video.srcObject = stream
      video.addEventListener("loadedmetadata", () => {
        video.play
      })
      videoGrid.append(video)
    }
  }
}

let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}, hooks: Hooks})

Where Next?

Popular in Questions Top

rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
nobody
How to bind a phoenix app to a specific ip address? could not find anything about that, nowhere, unfortunately, but for me this is quite...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" =&gt; #BSON.ObjectId&lt;58eb1a7a9ad169198c3dXXXX&gt;, "email" =&gt; ...
New
mgjohns61585
Could someone help me? I’m making my first elixir program, number guessing game. I can’t figure out how to convert the user’s guess from ...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

Other popular topics Top

KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36352 110
New
AstonJ
Please see the new poll here: Which code editor or IDE do you use? (Poll) (2022 Edition) It’s been a while since we first asked this, I...
208 31265 143
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43757 214
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement