Files
Rivertalk/lib/river_connect_web/channels/audio_channel.ex
T
2026-02-12 17:10:03 -06:00

80 lines
2.3 KiB
Elixir

defmodule RiverConnectWeb.AudioChannel do
use RiverConnectWeb, :channel
alias RiverConnect.Audio
@impl true
def join("audio:lobby", _payload, socket) do
{:ok, socket}
end
@impl true
def handle_in("audio_start", %{"id" => id}, socket) do
# Ensure upload directory exists
upload_path = Application.app_dir(:river_connect, "priv/static/uploads")
File.mkdir_p!(upload_path)
user_id = socket.assigns[:user_id] || "guest"
# Create DB record immediately with "recording" status
{:ok, message} =
Audio.create_message(%{
user_id: user_id,
file_path: "/uploads/#{id}.webm",
status: "recording"
})
# Store temporary file path and message_id in socket assigns
temp_file_path = Path.join(upload_path, "#{id}.webm")
# Broadcast start and new message to other listeners
broadcast_from!(socket, "audio_start", %{id: id})
broadcast!(socket, "audio_message_created", %{message: message})
{:noreply,
assign(socket, :current_recording, %{id: id, path: temp_file_path, message_id: message.id})}
end
@impl true
def handle_in("audio_chunk", {:binary, payload}, socket) do
case socket.assigns[:current_recording] do
%{path: path} ->
# Append binary chunk to file
File.write!(path, payload, [:append])
# Broadcast chunk to other listeners for live playback
broadcast_from!(socket, "audio_chunk", %{data: Base.encode64(payload)})
{:noreply, socket}
_ ->
{:noreply, socket}
end
end
@impl true
def handle_in("audio_end", %{"duration_ms" => duration_ms}, socket) do
case socket.assigns[:current_recording] do
%{message_id: message_id} ->
message = Audio.get_message!(message_id)
# Update DB record to "processing" status
{:ok, message} =
Audio.update_message(message, %{
duration_ms: duration_ms,
status: "processing"
})
# Queue Oban job for processing
%{id: message.id}
|> RiverConnect.Workers.ProcessRecording.new()
|> Oban.insert!()
# Notify UI that message status changed
broadcast!(socket, "audio_message_ready", %{id: message.id})
{:noreply, assign(socket, :current_recording, nil)}
_ ->
{:noreply, socket}
end
end
end