MatijaL
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})
Trending in Questions
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
Hello,
I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
Hi everyone,
I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding.
I sta...
New
Documentation
While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
So my question is quite simple and i have found no conclusive answer on forum, google or AI.
Should we use :erlang.float for Integer to ...
New
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
I’m new to elixir and just tried to install the elixirLS extension for VScode(ium) and it is throwing some errors that I would like help ...
New
Other Trending Topics
Edit: 2026 May 15 - This post is archived.
Mob is alive!!
Main docs: mob v0.7.11 — Documentation
A bit of explanation for the slightly c...
New
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
Hi there! We created Gust: A task orchestrator inspired by Airflow.
For those who have never heard about Aiflow, it’s a Python-based wor...
New
Hi everyone!
The first release candidate for the Expert language server project is now available!
We’ve published a press release detai...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #ai
- #elixirconf-us
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #elixirconf-eu
- #metaprogramming
- #hex










