From 4187afa77b71431c6f758f7048b019eddd3afe0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Tue, 16 Jan 2024 13:08:28 +0100 Subject: [PATCH 01/21] Add tracks to state --- lib/jellyfish/component.ex | 6 +- lib/jellyfish/peer.ex | 7 +- lib/jellyfish/room.ex | 70 ++++++++++++++----- lib/jellyfish/track.ex | 30 ++++++++ lib/jellyfish_web/api_spec/component/file.ex | 9 ++- lib/jellyfish_web/api_spec/component/hls.ex | 9 ++- lib/jellyfish_web/api_spec/component/rtsp.ex | 9 ++- lib/jellyfish_web/api_spec/peer.ex | 9 ++- lib/jellyfish_web/api_spec/track.ex | 28 ++++++++ .../controllers/component_json.ex | 3 +- lib/jellyfish_web/controllers/peer_json.ex | 3 +- openapi.yaml | 46 ++++++++++++ .../component/file_component_test.exs | 2 +- 13 files changed, 198 insertions(+), 33 deletions(-) create mode 100644 lib/jellyfish/track.ex create mode 100644 lib/jellyfish_web/api_spec/track.ex diff --git a/lib/jellyfish/component.ex b/lib/jellyfish/component.ex index ef4496ba..705ab67b 100644 --- a/lib/jellyfish/component.ex +++ b/lib/jellyfish/component.ex @@ -11,6 +11,7 @@ defmodule Jellyfish.Component do use Bunch.Access alias Jellyfish.Component.{File, HLS, RTSP} + alias Jellyfish.Track @enforce_keys [ :id, @@ -18,7 +19,7 @@ defmodule Jellyfish.Component do :engine_endpoint, :properties ] - defstruct @enforce_keys + defstruct @enforce_keys ++ [tracks: %{}] @type id :: String.t() @type component :: HLS | RTSP | File @@ -35,7 +36,8 @@ defmodule Jellyfish.Component do id: id(), type: component(), engine_endpoint: Membrane.ChildrenSpec.child_definition(), - properties: properties() + properties: properties(), + tracks: %{Track.id() => Track.t()} } @spec parse_type(String.t()) :: {:ok, component()} | {:error, :invalid_type} diff --git a/lib/jellyfish/peer.ex b/lib/jellyfish/peer.ex index 5fd2ea1e..38764d56 100644 --- a/lib/jellyfish/peer.ex +++ b/lib/jellyfish/peer.ex @@ -3,15 +3,17 @@ defmodule Jellyfish.Peer do Peer is an entity that connects to the server to publish, subscribe or publish and subscribe to tracks published by producers or other peers. Peer process is spawned after peer connects to the server. """ + use Bunch.Access alias Jellyfish.Peer.WebRTC + alias Jellyfish.Track @enforce_keys [ :id, :type, :engine_endpoint ] - defstruct @enforce_keys ++ [status: :disconnected, socket_pid: nil] + defstruct @enforce_keys ++ [status: :disconnected, socket_pid: nil, tracks: %{}] @type id :: String.t() @type peer :: WebRTC @@ -28,7 +30,8 @@ defmodule Jellyfish.Peer do type: peer(), status: status(), socket_pid: pid() | nil, - engine_endpoint: Membrane.ChildrenSpec.child_definition() + engine_endpoint: Membrane.ChildrenSpec.child_definition(), + tracks: %{Track.id() => Track.t()} } @spec parse_type(String.t()) :: {:ok, peer()} | {:error, :invalid_type} diff --git a/lib/jellyfish/room.ex b/lib/jellyfish/room.ex index 658d003a..e79007c1 100644 --- a/lib/jellyfish/room.ex +++ b/lib/jellyfish/room.ex @@ -13,6 +13,7 @@ defmodule Jellyfish.Room do alias Jellyfish.Event alias Jellyfish.Peer alias Jellyfish.Room.Config + alias Jellyfish.Track alias Membrane.ICE.TURNManager alias Membrane.RTC.Engine @@ -367,19 +368,21 @@ defmodule Jellyfish.Room do def handle_info(%EndpointCrashed{endpoint_id: endpoint_id}, state) do Logger.error("RTC Engine endpoint #{inspect(endpoint_id)} crashed") - if Map.has_key?(state.peers, endpoint_id) do - Event.broadcast_server_notification({:peer_crashed, state.id, endpoint_id}) + case get_endpoint_type(state, endpoint_id) do + :peer -> + Event.broadcast_server_notification({:peer_crashed, state.id, endpoint_id}) - peer = Map.fetch!(state.peers, endpoint_id) + peer = Map.fetch!(state.peers, endpoint_id) - if peer.socket_pid != nil do - send(peer.socket_pid, {:stop_connection, :endpoint_crashed}) - end - else - Event.broadcast_server_notification({:component_crashed, state.id, endpoint_id}) + if peer.socket_pid != nil do + send(peer.socket_pid, {:stop_connection, :endpoint_crashed}) + end - component = Map.get(state.components, endpoint_id) - if component.type == HLS, do: on_hls_removal(state.id, component.properties) + :component -> + Event.broadcast_server_notification({:component_crashed, state.id, endpoint_id}) + + component = Map.get(state.components, endpoint_id) + if component.type == HLS, do: on_hls_removal(state.id, component.properties) end {:noreply, state} @@ -436,23 +439,28 @@ defmodule Jellyfish.Room do end @impl true - def handle_info( - %EndpointAdded{endpoint_id: endpoint_id}, - state - ) + def handle_info(%EndpointAdded{endpoint_id: endpoint_id}, state) when endpoint_exists?(state, endpoint_id) do {:noreply, state} end @impl true - def handle_info(%TrackAdded{} = track_info, state) do - Logger.info("Endpoint #{track_info.endpoint_id} added track #{inspect(track_info)}") + def handle_info(%TrackAdded{endpoint_id: endpoint_id} = track_info, state) + when endpoint_exists?(state, endpoint_id) do + Logger.info("Endpoint #{endpoint_id} added track #{inspect(track_info)}") + + state = add_track(state, track_info) + {:noreply, state} end @impl true - def handle_info(%TrackRemoved{} = track_info, state) do - Logger.info("Endpoint #{track_info.endpoint_id} removed track #{inspect(track_info)}") + def handle_info(%TrackRemoved{endpoint_id: endpoint_id} = track_info, state) + when endpoint_exists?(state, endpoint_id) do + Logger.info("Endpoint #{endpoint_id} removed track #{inspect(track_info)}") + + state = remove_track(state, track_info) + {:noreply, state} end @@ -578,4 +586,30 @@ defmodule Jellyfish.Room do do: {:error, :invalid_subscribe_mode} defp validate_hls_subscription(%{properties: %{subscribe_mode: :manual}}), do: :ok + + defp get_endpoint_type(state, endpoint_id) when is_map_key(state.components, endpoint_id), + do: :component + + defp get_endpoint_type(state, endpoint_id) when is_map_key(state.peers, endpoint_id), + do: :peer + + defp add_track(state, track_info) do + track = Track.from_track_added_message(track_info) + put_in(state, get_track_keys(state, track_info), track) + end + + defp remove_track(state, track_info) do + {_track, state} = pop_in(state, get_track_keys(state, track_info)) + state + end + + defp get_track_keys(state, track_info) do + endpoints_type = + case get_endpoint_type(state, track_info.endpoint_id) do + :component -> :components + :peer -> :peers + end + + [endpoints_type, track_info.endpoint_id, :tracks, track_info.track_id] + end end diff --git a/lib/jellyfish/track.ex b/lib/jellyfish/track.ex new file mode 100644 index 00000000..9ede17b8 --- /dev/null +++ b/lib/jellyfish/track.ex @@ -0,0 +1,30 @@ +defmodule Jellyfish.Track do + @moduledoc """ + Represents a media track send from Component or Peer. + """ + + use Bunch.Access + + alias Membrane.RTC.Engine.Message.TrackAdded + + @enforce_keys [:id, :type, :encoding] + defstruct @enforce_keys ++ [:metadata] + + @type id() :: String.t() + + @type t() :: %__MODULE__{ + id: id(), + type: :audio | :video, + encoding: atom(), + metadata: nil | any() + } + + @spec from_track_added_message(TrackAdded.t()) :: t() + def from_track_added_message(message) do + %__MODULE__{ + id: message.track_id, + type: message.track_type, + encoding: message.track_encoding + } + end +end diff --git a/lib/jellyfish_web/api_spec/component/file.ex b/lib/jellyfish_web/api_spec/component/file.ex index 7f41af30..d667e10c 100644 --- a/lib/jellyfish_web/api_spec/component/file.ex +++ b/lib/jellyfish_web/api_spec/component/file.ex @@ -53,8 +53,13 @@ defmodule JellyfishWeb.ApiSpec.Component.File do id: %Schema{type: :string, description: "Assigned component ID", example: "component-1"}, # FIXME: due to cyclic imports, we can't use ApiSpec.Component.Type here type: %Schema{type: :string, description: "Component type", example: "file"}, - properties: Properties + properties: Properties, + tracks: %Schema{ + type: :array, + items: JellyfishWeb.ApiSpec.Track, + description: "List of all component's tracks" + } }, - required: [:id, :type] + required: [:id, :type, :tracks] }) end diff --git a/lib/jellyfish_web/api_spec/component/hls.ex b/lib/jellyfish_web/api_spec/component/hls.ex index 8d74f9aa..9eca9cb5 100644 --- a/lib/jellyfish_web/api_spec/component/hls.ex +++ b/lib/jellyfish_web/api_spec/component/hls.ex @@ -126,8 +126,13 @@ defmodule JellyfishWeb.ApiSpec.Component.HLS do id: %Schema{type: :string, description: "Assigned component ID", example: "component-1"}, # FIXME: due to cyclic imports, we can't use ApiSpec.Component.Type here type: %Schema{type: :string, description: "Component type", example: "hls"}, - properties: Properties + properties: Properties, + tracks: %Schema{ + type: :array, + items: JellyfishWeb.ApiSpec.Track, + description: "List of all component's tracks" + } }, - required: [:id, :type, :properties] + required: [:id, :type, :properties, :tracks] }) end diff --git a/lib/jellyfish_web/api_spec/component/rtsp.ex b/lib/jellyfish_web/api_spec/component/rtsp.ex index 336a1f60..1ee98028 100644 --- a/lib/jellyfish_web/api_spec/component/rtsp.ex +++ b/lib/jellyfish_web/api_spec/component/rtsp.ex @@ -96,8 +96,13 @@ defmodule JellyfishWeb.ApiSpec.Component.RTSP do id: %Schema{type: :string, description: "Assigned component ID", example: "component-1"}, # FIXME: due to cyclic imports, we can't use ApiSpec.Component.Type here type: %Schema{type: :string, description: "Component type", example: "hls"}, - properties: Properties + properties: Properties, + tracks: %Schema{ + type: :array, + items: JellyfishWeb.ApiSpec.Track, + description: "List of all component's tracks" + } }, - required: [:id, :type, :properties] + required: [:id, :type, :properties, :tracks] }) end diff --git a/lib/jellyfish_web/api_spec/peer.ex b/lib/jellyfish_web/api_spec/peer.ex index 54c22d49..fdf37aa3 100644 --- a/lib/jellyfish_web/api_spec/peer.ex +++ b/lib/jellyfish_web/api_spec/peer.ex @@ -68,8 +68,13 @@ defmodule JellyfishWeb.ApiSpec.Peer do properties: %{ id: %Schema{type: :string, description: "Assigned peer id", example: "peer-1"}, type: Type, - status: Status + status: Status, + tracks: %Schema{ + type: :array, + items: JellyfishWeb.ApiSpec.Track, + description: "List of all peer's tracks" + } }, - required: [:id, :type, :status] + required: [:id, :type, :status, :tracks] }) end diff --git a/lib/jellyfish_web/api_spec/track.ex b/lib/jellyfish_web/api_spec/track.ex new file mode 100644 index 00000000..8d96ef65 --- /dev/null +++ b/lib/jellyfish_web/api_spec/track.ex @@ -0,0 +1,28 @@ +defmodule JellyfishWeb.ApiSpec.Track do + require OpenApiSpex + + alias OpenApiSpex.Schema + + OpenApiSpex.schema(%{ + title: "Track", + description: "Describes media track of a Peer or Component", + type: :object, + properties: %{ + id: %Schema{ + type: :string + }, + type: %Schema{ + type: :string, + enum: ["audio", "video"] + }, + encoding: %Schema{ + type: :string, + enum: ["H264", "VP8", "OPUS"] + }, + metadata: %Schema{ + type: :string, + nullable: true + } + } + }) +end diff --git a/lib/jellyfish_web/controllers/component_json.ex b/lib/jellyfish_web/controllers/component_json.ex index 7d28be3f..15bade2f 100644 --- a/lib/jellyfish_web/controllers/component_json.ex +++ b/lib/jellyfish_web/controllers/component_json.ex @@ -19,7 +19,8 @@ defmodule JellyfishWeb.ComponentJSON do %{ id: component.id, type: type, - properties: component.properties |> ParserJSON.camel_case_keys() + properties: component.properties |> ParserJSON.camel_case_keys(), + tracks: component.tracks |> Map.values() |> Enum.map(&Map.from_struct/1) } end end diff --git a/lib/jellyfish_web/controllers/peer_json.ex b/lib/jellyfish_web/controllers/peer_json.ex index b12bb02a..6ebf47c1 100644 --- a/lib/jellyfish_web/controllers/peer_json.ex +++ b/lib/jellyfish_web/controllers/peer_json.ex @@ -19,7 +19,8 @@ defmodule JellyfishWeb.PeerJSON do %{ id: peer.id, type: type, - status: "#{peer.status}" + status: "#{peer.status}", + tracks: peer.tracks |> Map.values() |> Enum.map(&Map.from_struct/1) } end end diff --git a/openapi.yaml b/openapi.yaml index f0874e6b..7ac45ff4 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -148,6 +148,11 @@ components: type: string properties: $ref: '#/components/schemas/ComponentPropertiesHLS' + tracks: + description: List of all component's tracks + items: + $ref: '#/components/schemas/Track' + type: array type: description: Component type example: hls @@ -156,6 +161,7 @@ components: - id - type - properties + - tracks title: ComponentHLS type: object x-struct: Elixir.JellyfishWeb.ApiSpec.Component.HLS @@ -186,6 +192,11 @@ components: type: string properties: $ref: '#/components/schemas/ComponentPropertiesFile' + tracks: + description: List of all component's tracks + items: + $ref: '#/components/schemas/Track' + type: array type: description: Component type example: file @@ -193,6 +204,7 @@ components: required: - id - type + - tracks title: ComponentFile type: object x-struct: Elixir.JellyfishWeb.ApiSpec.Component.File @@ -224,6 +236,11 @@ components: type: string properties: $ref: '#/components/schemas/ComponentPropertiesRTSP' + tracks: + description: List of all component's tracks + items: + $ref: '#/components/schemas/Track' + type: array type: description: Component type example: hls @@ -232,6 +249,7 @@ components: - id - type - properties + - tracks title: ComponentRTSP type: object x-struct: Elixir.JellyfishWeb.ApiSpec.Component.RTSP @@ -328,6 +346,28 @@ components: title: ComponentOptions type: object x-struct: Elixir.JellyfishWeb.ApiSpec.Component.Options + Track: + description: Describes media track of a Peer or Component + properties: + encoding: + enum: + - H264 + - VP8 + - OPUS + type: string + id: + type: string + metadata: + nullable: true + type: string + type: + enum: + - audio + - video + type: string + title: Track + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.Track ComponentPropertiesRTSP: description: Properties specific to the RTSP component properties: @@ -371,12 +411,18 @@ components: type: string status: $ref: '#/components/schemas/PeerStatus' + tracks: + description: List of all peer's tracks + items: + $ref: '#/components/schemas/Track' + type: array type: $ref: '#/components/schemas/PeerType' required: - id - type - status + - tracks title: Peer type: object x-struct: Elixir.JellyfishWeb.ApiSpec.Peer diff --git a/test/jellyfish_web/controllers/component/file_component_test.exs b/test/jellyfish_web/controllers/component/file_component_test.exs index d0008c6a..11815235 100644 --- a/test/jellyfish_web/controllers/component/file_component_test.exs +++ b/test/jellyfish_web/controllers/component/file_component_test.exs @@ -49,7 +49,7 @@ defmodule JellyfishWeb.Component.FileComponentTest do assert_component_created(conn, room_id, id, "file") end - test "renders component wiht audio as source", %{conn: conn, room_id: room_id} do + test "renders component with audio as source", %{conn: conn, room_id: room_id} do conn = post(conn, ~p"/room/#{room_id}/component", type: "file", From e89376ea0f0beb2969942afe2ecc6205bb58d7da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Tue, 16 Jan 2024 13:46:15 +0100 Subject: [PATCH 02/21] Add track metadata --- lib/jellyfish/room.ex | 38 +++++++++++++++++------------ lib/jellyfish/track.ex | 11 +++++++++ lib/jellyfish_web/api_spec/track.ex | 1 + 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/lib/jellyfish/room.ex b/lib/jellyfish/room.ex index e79007c1..e0738a1c 100644 --- a/lib/jellyfish/room.ex +++ b/lib/jellyfish/room.ex @@ -148,7 +148,10 @@ defmodule Jellyfish.Room do @impl true def handle_call(:get_state, _from, state) do - {:reply, state, state} + all_tracks = Engine.get_tracks(state.engine_pid) + response = update_with_track_metadata(state, all_tracks) + + {:reply, response, state} end @impl true @@ -368,8 +371,8 @@ defmodule Jellyfish.Room do def handle_info(%EndpointCrashed{endpoint_id: endpoint_id}, state) do Logger.error("RTC Engine endpoint #{inspect(endpoint_id)} crashed") - case get_endpoint_type(state, endpoint_id) do - :peer -> + case get_endpoint_group(state, endpoint_id) do + :peers -> Event.broadcast_server_notification({:peer_crashed, state.id, endpoint_id}) peer = Map.fetch!(state.peers, endpoint_id) @@ -378,7 +381,7 @@ defmodule Jellyfish.Room do send(peer.socket_pid, {:stop_connection, :endpoint_crashed}) end - :component -> + :components -> Event.broadcast_server_notification({:component_crashed, state.id, endpoint_id}) component = Map.get(state.components, endpoint_id) @@ -587,11 +590,21 @@ defmodule Jellyfish.Room do defp validate_hls_subscription(%{properties: %{subscribe_mode: :manual}}), do: :ok - defp get_endpoint_type(state, endpoint_id) when is_map_key(state.components, endpoint_id), - do: :component + defp update_with_track_metadata(state, tracks) do + Enum.reduce(tracks, state, fn engine_track, state -> + track = Track.from_engine_track(engine_track) + endpoint_id = engine_track.origin + endpoint_group = get_endpoint_group(state, endpoint_id) + + put_in(state, [endpoint_group, endpoint_id, :tracks, track.id], track) + end) + end + + defp get_endpoint_group(state, endpoint_id) when is_map_key(state.components, endpoint_id), + do: :components - defp get_endpoint_type(state, endpoint_id) when is_map_key(state.peers, endpoint_id), - do: :peer + defp get_endpoint_group(state, endpoint_id) when is_map_key(state.peers, endpoint_id), + do: :peers defp add_track(state, track_info) do track = Track.from_track_added_message(track_info) @@ -604,12 +617,7 @@ defmodule Jellyfish.Room do end defp get_track_keys(state, track_info) do - endpoints_type = - case get_endpoint_type(state, track_info.endpoint_id) do - :component -> :components - :peer -> :peers - end - - [endpoints_type, track_info.endpoint_id, :tracks, track_info.track_id] + endpoint_group = get_endpoint_group(state, track_info.endpoint_id) + [endpoint_group, track_info.endpoint_id, :tracks, track_info.track_id] end end diff --git a/lib/jellyfish/track.ex b/lib/jellyfish/track.ex index 9ede17b8..c5661787 100644 --- a/lib/jellyfish/track.ex +++ b/lib/jellyfish/track.ex @@ -6,6 +6,7 @@ defmodule Jellyfish.Track do use Bunch.Access alias Membrane.RTC.Engine.Message.TrackAdded + alias Membrane.RTC.Engine.Track @enforce_keys [:id, :type, :encoding] defstruct @enforce_keys ++ [:metadata] @@ -27,4 +28,14 @@ defmodule Jellyfish.Track do encoding: message.track_encoding } end + + @spec from_engine_track(Track.t()) :: t() + def from_engine_track(engine_track) do + %__MODULE__{ + id: engine_track.id, + type: engine_track.type, + encoding: engine_track.encoding, + metadata: engine_track.metadata + } + end end diff --git a/lib/jellyfish_web/api_spec/track.ex b/lib/jellyfish_web/api_spec/track.ex index 8d96ef65..3ae140b0 100644 --- a/lib/jellyfish_web/api_spec/track.ex +++ b/lib/jellyfish_web/api_spec/track.ex @@ -1,4 +1,5 @@ defmodule JellyfishWeb.ApiSpec.Track do + @moduledoc false require OpenApiSpex alias OpenApiSpex.Schema From ba816cf384779bf5f75e0b72dbc73fc9fb9848ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Thu, 18 Jan 2024 10:12:01 +0100 Subject: [PATCH 03/21] Log errors --- lib/jellyfish/room.ex | 46 ++++++++++++++++++++--------- lib/jellyfish/track.ex | 11 ------- lib/jellyfish_web/api_spec/track.ex | 1 - openapi.yaml | 1 - 4 files changed, 32 insertions(+), 27 deletions(-) diff --git a/lib/jellyfish/room.ex b/lib/jellyfish/room.ex index e0738a1c..df49f800 100644 --- a/lib/jellyfish/room.ex +++ b/lib/jellyfish/room.ex @@ -371,21 +371,19 @@ defmodule Jellyfish.Room do def handle_info(%EndpointCrashed{endpoint_id: endpoint_id}, state) do Logger.error("RTC Engine endpoint #{inspect(endpoint_id)} crashed") - case get_endpoint_group(state, endpoint_id) do - :peers -> - Event.broadcast_server_notification({:peer_crashed, state.id, endpoint_id}) + if Map.has_key?(state.peers, endpoint_id) do + Event.broadcast_server_notification({:peer_crashed, state.id, endpoint_id}) - peer = Map.fetch!(state.peers, endpoint_id) + peer = Map.fetch!(state.peers, endpoint_id) - if peer.socket_pid != nil do - send(peer.socket_pid, {:stop_connection, :endpoint_crashed}) - end - - :components -> - Event.broadcast_server_notification({:component_crashed, state.id, endpoint_id}) + if peer.socket_pid != nil do + send(peer.socket_pid, {:stop_connection, :endpoint_crashed}) + end + else + Event.broadcast_server_notification({:component_crashed, state.id, endpoint_id}) - component = Map.get(state.components, endpoint_id) - if component.type == HLS, do: on_hls_removal(state.id, component.properties) + component = Map.get(state.components, endpoint_id) + if component.type == HLS, do: on_hls_removal(state.id, component.properties) end {:noreply, state} @@ -457,6 +455,12 @@ defmodule Jellyfish.Room do {:noreply, state} end + @impl true + def handle_info(%TrackAdded{endpoint_id: endpoint_id} = track_info, state) do + Logger.error("Unknown endpoint #{endpoint_id} added track #{inspect(track_info)}") + {:noreply, state} + end + @impl true def handle_info(%TrackRemoved{endpoint_id: endpoint_id} = track_info, state) when endpoint_exists?(state, endpoint_id) do @@ -467,6 +471,12 @@ defmodule Jellyfish.Room do {:noreply, state} end + @impl true + def handle_info(%TrackRemoved{endpoint_id: endpoint_id} = track_info, state) do + Logger.error("Unknown endpoint #{endpoint_id} removed track #{inspect(track_info)}") + {:noreply, state} + end + @impl true def handle_info(info, state) do Logger.warning("Received unexpected info: #{inspect(info)}") @@ -592,11 +602,19 @@ defmodule Jellyfish.Room do defp update_with_track_metadata(state, tracks) do Enum.reduce(tracks, state, fn engine_track, state -> - track = Track.from_engine_track(engine_track) endpoint_id = engine_track.origin + track_id = engine_track.id endpoint_group = get_endpoint_group(state, endpoint_id) - put_in(state, [endpoint_group, endpoint_id, :tracks, track.id], track) + update_in(state, [endpoint_group, endpoint_id, :tracks, track_id], fn + nil -> + Logger.warning( + "Unable to update track's metadata - track #{inspect(track_id)} doesn't exist" + ) + + track -> + %Track{track | metadata: engine_track.metadata} + end) end) end diff --git a/lib/jellyfish/track.ex b/lib/jellyfish/track.ex index c5661787..9ede17b8 100644 --- a/lib/jellyfish/track.ex +++ b/lib/jellyfish/track.ex @@ -6,7 +6,6 @@ defmodule Jellyfish.Track do use Bunch.Access alias Membrane.RTC.Engine.Message.TrackAdded - alias Membrane.RTC.Engine.Track @enforce_keys [:id, :type, :encoding] defstruct @enforce_keys ++ [:metadata] @@ -28,14 +27,4 @@ defmodule Jellyfish.Track do encoding: message.track_encoding } end - - @spec from_engine_track(Track.t()) :: t() - def from_engine_track(engine_track) do - %__MODULE__{ - id: engine_track.id, - type: engine_track.type, - encoding: engine_track.encoding, - metadata: engine_track.metadata - } - end end diff --git a/lib/jellyfish_web/api_spec/track.ex b/lib/jellyfish_web/api_spec/track.ex index 3ae140b0..7012407b 100644 --- a/lib/jellyfish_web/api_spec/track.ex +++ b/lib/jellyfish_web/api_spec/track.ex @@ -21,7 +21,6 @@ defmodule JellyfishWeb.ApiSpec.Track do enum: ["H264", "VP8", "OPUS"] }, metadata: %Schema{ - type: :string, nullable: true } } diff --git a/openapi.yaml b/openapi.yaml index 7ac45ff4..020433d2 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -359,7 +359,6 @@ components: type: string metadata: nullable: true - type: string type: enum: - audio From 1f683cefc36d256a64debad693518cf0505bd057 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Thu, 18 Jan 2024 13:03:38 +0100 Subject: [PATCH 04/21] Fix openapi lint --- .redocly.lint-ignore.yaml | 2 ++ lib/jellyfish/room.ex | 16 +++++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.redocly.lint-ignore.yaml b/.redocly.lint-ignore.yaml index 782ee7a1..c58c898a 100644 --- a/.redocly.lint-ignore.yaml +++ b/.redocly.lint-ignore.yaml @@ -3,3 +3,5 @@ openapi.yaml: no-empty-servers: - '#/servers' + spec: + - '#/components/schemas/Track/properties/metadata/nullable' diff --git a/lib/jellyfish/room.ex b/lib/jellyfish/room.ex index df49f800..390e72e3 100644 --- a/lib/jellyfish/room.ex +++ b/lib/jellyfish/room.ex @@ -602,19 +602,21 @@ defmodule Jellyfish.Room do defp update_with_track_metadata(state, tracks) do Enum.reduce(tracks, state, fn engine_track, state -> - endpoint_id = engine_track.origin - track_id = engine_track.id - endpoint_group = get_endpoint_group(state, endpoint_id) + endpoint_group = get_endpoint_group(state, engine_track.origin) + access_path = [endpoint_group, engine_track.origin, :tracks, engine_track.id] - update_in(state, [endpoint_group, endpoint_id, :tracks, track_id], fn + case get_in(state, access_path) do nil -> Logger.warning( - "Unable to update track's metadata - track #{inspect(track_id)} doesn't exist" + "Unable to update track's metadata - track #{inspect(engine_track.id)} doesn't exist" ) + state + track -> - %Track{track | metadata: engine_track.metadata} - end) + track = %Track{track | metadata: engine_track.metadata} + put_in(state, access_path, track) + end end) end From 7a329ccd8dbb26082b38d001d74e626970c14d7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Wed, 24 Jan 2024 13:56:19 +0100 Subject: [PATCH 05/21] Add track meta --- config/dev.exs | 2 ++ lib/jellyfish/peer.ex | 5 +++-- lib/jellyfish/room.ex | 42 ++++++++++++++++++++++++++++++++++++++---- lib/jellyfish/track.ex | 3 ++- mix.exs | 2 +- mix.lock | 23 ++++++++++++----------- 6 files changed, 58 insertions(+), 19 deletions(-) diff --git a/config/dev.exs b/config/dev.exs index 8846bb1c..550fd318 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -26,3 +26,5 @@ config :phoenix, :stacktrace_depth, 20 # Initialize plugs at runtime for faster development compilation config :phoenix, :plug_init_mode, :runtime + +config :logger, level: :info diff --git a/lib/jellyfish/peer.ex b/lib/jellyfish/peer.ex index 38764d56..621fee58 100644 --- a/lib/jellyfish/peer.ex +++ b/lib/jellyfish/peer.ex @@ -13,7 +13,7 @@ defmodule Jellyfish.Peer do :type, :engine_endpoint ] - defstruct @enforce_keys ++ [status: :disconnected, socket_pid: nil, tracks: %{}] + defstruct @enforce_keys ++ [status: :disconnected, socket_pid: nil, tracks: %{}, metadata: nil] @type id :: String.t() @type peer :: WebRTC @@ -31,7 +31,8 @@ defmodule Jellyfish.Peer do status: status(), socket_pid: pid() | nil, engine_endpoint: Membrane.ChildrenSpec.child_definition(), - tracks: %{Track.id() => Track.t()} + tracks: %{Track.id() => Track.t()}, + metadata: any() } @spec parse_type(String.t()) :: {:ok, peer()} | {:error, :invalid_type} diff --git a/lib/jellyfish/room.ex b/lib/jellyfish/room.ex index 390e72e3..21a36991 100644 --- a/lib/jellyfish/room.ex +++ b/lib/jellyfish/room.ex @@ -20,10 +20,12 @@ defmodule Jellyfish.Room do alias Membrane.RTC.Engine.Message.{ EndpointAdded, + EndpointMetadataUpdated, EndpointCrashed, EndpointMessage, EndpointRemoved, TrackAdded, + TrackMetadataUpdated, TrackRemoved } @@ -148,10 +150,7 @@ defmodule Jellyfish.Room do @impl true def handle_call(:get_state, _from, state) do - all_tracks = Engine.get_tracks(state.engine_pid) - response = update_with_track_metadata(state, all_tracks) - - {:reply, response, state} + {:reply, state, state} end @impl true @@ -445,6 +444,18 @@ defmodule Jellyfish.Room do {:noreply, state} end + @impl true + def handle_info( + %EndpointMetadataUpdated{endpoint_id: endpoint_id, endpoint_metadata: metadata}, + state + ) + when endpoint_exists?(state, endpoint_id) do + endpoint_group = get_endpoint_group(state, endpoint_id) + + state = put_in(state, [endpoint_group, endpoint_id, :metadata], metadata) + {:noreply, state} + end + @impl true def handle_info(%TrackAdded{endpoint_id: endpoint_id} = track_info, state) when endpoint_exists?(state, endpoint_id) do @@ -461,6 +472,29 @@ defmodule Jellyfish.Room do {:noreply, state} end + @impl true + def handle_info(%TrackMetadataUpdated{endpoint_id: endpoint_id} = track_info, state) + when endpoint_exists?(state, endpoint_id) do + endpoint_group = get_endpoint_group(state, endpoint_id) + access_path = [endpoint_group, endpoint_id, :tracks, track_info.track_id] + + state = + case get_in(state, access_path) do + nil -> + Logger.warning( + "Unable to update track's metadata - track #{inspect(track_info.track_id)} doesn't exist" + ) + + state + + track -> + track = %Track{track | metadata: track_info.track_metadata} + put_in(state, access_path, track) + end + + {:noreply, state} + end + @impl true def handle_info(%TrackRemoved{endpoint_id: endpoint_id} = track_info, state) when endpoint_exists?(state, endpoint_id) do diff --git a/lib/jellyfish/track.ex b/lib/jellyfish/track.ex index 9ede17b8..cee1dd1c 100644 --- a/lib/jellyfish/track.ex +++ b/lib/jellyfish/track.ex @@ -24,7 +24,8 @@ defmodule Jellyfish.Track do %__MODULE__{ id: message.track_id, type: message.track_type, - encoding: message.track_encoding + encoding: message.track_encoding, + metadata: message.track_metadata } end end diff --git a/mix.exs b/mix.exs index e53db4fb..7b79200b 100644 --- a/mix.exs +++ b/mix.exs @@ -68,7 +68,7 @@ defmodule Jellyfish.MixProject do {:protobuf, "~> 0.12.0"}, # Membrane deps - {:membrane_rtc_engine, "~> 0.19.0"}, + {:membrane_rtc_engine, path: "../membrane_rtc_engine/engine", override: true}, {:membrane_rtc_engine_webrtc, "~> 0.5.0"}, {:membrane_rtc_engine_hls, "~> 0.4.0"}, {:membrane_rtc_engine_rtsp, "~> 0.4.0"}, diff --git a/mix.lock b/mix.lock index 67905386..9587ce47 100644 --- a/mix.lock +++ b/mix.lock @@ -2,9 +2,9 @@ "bimap": {:hex, :bimap, "1.3.0", "3ea4832e58dc83a9b5b407c6731e7bae87458aa618e6d11d8e12114a17afa4b3", [:mix], [], "hexpm", "bf5a2b078528465aa705f405a5c638becd63e41d280ada41e0f77e6d255a10b4"}, "bunch": {:hex, :bunch, "1.6.1", "5393d827a64d5f846092703441ea50e65bc09f37fd8e320878f13e63d410aec7", [:mix], [], "hexpm", "286cc3add551628b30605efbe2fca4e38cc1bea89bcd0a1a7226920b3364fe4a"}, "bunch_native": {:hex, :bunch_native, "0.5.0", "8ac1536789a597599c10b652e0b526d8833348c19e4739a0759a2bedfd924e63", [:mix], [{:bundlex, "~> 1.0", [hex: :bundlex, repo: "hexpm", optional: false]}], "hexpm", "24190c760e32b23b36edeb2dc4852515c7c5b3b8675b1a864e0715bdd1c8f80d"}, - "bundlex": {:hex, :bundlex, "1.3.2", "3fe5de1a96a353b0bc2ea676703f435d955afc466d61a128a887330814434920", [:mix], [{:bunch, "~> 1.0", [hex: :bunch, repo: "hexpm", optional: false]}, {:elixir_uuid, "~> 1.2", [hex: :elixir_uuid, repo: "hexpm", optional: false]}, {:qex, "~> 0.5", [hex: :qex, repo: "hexpm", optional: false]}, {:req, "~> 0.4.0", [hex: :req, repo: "hexpm", optional: false]}, {:zarex, "~> 1.0", [hex: :zarex, repo: "hexpm", optional: false]}], "hexpm", "3806324386d75a0a8451ef3573707af6f30749a361bcf6ea093223c3f9e309fe"}, + "bundlex": {:hex, :bundlex, "1.4.5", "ea06cb441af636baaf5232dced24c6b1ee5ccbe7a7cad8a348eb3100fa1d7b52", [:mix], [{:bunch, "~> 1.0", [hex: :bunch, repo: "hexpm", optional: false]}, {:elixir_uuid, "~> 1.2", [hex: :elixir_uuid, repo: "hexpm", optional: false]}, {:qex, "~> 0.5", [hex: :qex, repo: "hexpm", optional: false]}, {:req, "~> 0.4.0", [hex: :req, repo: "hexpm", optional: false]}, {:zarex, "~> 1.0", [hex: :zarex, repo: "hexpm", optional: false]}], "hexpm", "bd4136100d3120740bf8eaa73ad74859d5ccd659cf0b27aa1645590a67a0172b"}, "bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"}, - "castore": {:hex, :castore, "1.0.4", "ff4d0fb2e6411c0479b1d965a814ea6d00e51eb2f58697446e9c41a97d940b28", [:mix], [], "hexpm", "9418c1b8144e11656f0be99943db4caf04612e3eaecefb5dae9a2a87565584f8"}, + "castore": {:hex, :castore, "1.0.5", "9eeebb394cc9a0f3ae56b813459f990abb0a3dedee1be6b27fdb50301930502f", [:mix], [], "hexpm", "8d7c597c3e4a64c395980882d4bca3cebb8d74197c590dc272cfd3b6a6310578"}, "certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"}, "coerce": {:hex, :coerce, "1.0.1", "211c27386315dc2894ac11bc1f413a0e38505d808153367bd5c6e75a4003d096", [:mix], [], "hexpm", "b44a691700f7a1a15b4b7e2ff1fa30bebd669929ac8aa43cffe9e2f8bf051cf1"}, "connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"}, @@ -22,13 +22,13 @@ "ex_aws": {:hex, :ex_aws, "2.5.0", "1785e69350b16514c1049330537c7da10039b1a53e1d253bbd703b135174aec3", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8 or ~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:mime, "~> 1.2 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "971b86e5495fc0ae1c318e35e23f389e74cf322f2c02d34037c6fc6d405006f1"}, "ex_aws_s3": {:hex, :ex_aws_s3, "2.5.2", "cee302b8e9ee198cc0d89f1de2a7d6a8921e1a556574476cf5590d2156590fe3", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "cc5bd945a22a99eece4721d734ae2452d3717e81c357a781c8574663254df4a1"}, "ex_dtls": {:hex, :ex_dtls, "0.12.0", "648522f53340b42301eae57627bb8276555be508ec1010561e606b1621d9d2e9", [:mix], [{:unifex, "~> 1.0", [hex: :unifex, repo: "hexpm", optional: false]}], "hexpm", "0bc2d0de146e7cf9d85eb8d2c0a6a518479a66a2ded8a79c0960eced23fe73a9"}, - "ex_libsrtp": {:hex, :ex_libsrtp, "0.7.1", "7b6f290fff53aae1021e19d584d29d33fba8dada59bca5e20fcbe24c675297d6", [:mix], [{:bunch, "~> 1.6", [hex: :bunch, repo: "hexpm", optional: false]}, {:bundlex, "~> 1.3", [hex: :bundlex, repo: "hexpm", optional: false]}, {:unifex, "~> 1.1", [hex: :unifex, repo: "hexpm", optional: false]}], "hexpm", "bd3d56e8933bea02300b91fa6d3bed3e1f456ec1efae83fb58a143ba07a24d7c"}, + "ex_libsrtp": {:hex, :ex_libsrtp, "0.7.2", "211bd89c08026943ce71f3e2c0231795b99cee748808ed3ae7b97cd8d2450b6b", [:mix], [{:bunch, "~> 1.6", [hex: :bunch, repo: "hexpm", optional: false]}, {:bundlex, "~> 1.3", [hex: :bundlex, repo: "hexpm", optional: false]}, {:membrane_precompiled_dependency_provider, "~> 0.1.0", [hex: :membrane_precompiled_dependency_provider, repo: "hexpm", optional: false]}, {:unifex, "~> 1.1", [hex: :unifex, repo: "hexpm", optional: false]}], "hexpm", "2e20645d0d739a4ecdcf8d4810a0c198120c8a2f617f2b75b2e2e704d59f492a"}, "ex_sdp": {:hex, :ex_sdp, "0.13.1", "8f8ea458694660fae5e687444b484f34ff2981401c5d11a64a8a3e004c4d53f1", [:mix], [{:bunch, "~> 1.3", [hex: :bunch, repo: "hexpm", optional: false]}, {:elixir_uuid, "~> 1.2", [hex: :elixir_uuid, repo: "hexpm", optional: false]}], "hexpm", "a3d66221e2aed4ea4efff98a9a6b52613b4d2eb10937d46bd2d1cae99a8f183b"}, "excoveralls": {:hex, :excoveralls, "0.15.3", "54bb54043e1cf5fe431eb3db36b25e8fd62cf3976666bafe491e3fa5e29eba47", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "f8eb5d8134d84c327685f7bb8f1db4147f1363c3c9533928234e496e3070114e"}, "fake_turn": {:hex, :fake_turn, "0.4.1", "8ca4677c8ca242055aa37048e6e2983bd369d591cad1450963e640edf89c1ab7", [:rebar3], [{:fast_tls, "1.1.13", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.23", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "dcba3f798c5c7dc25462982a9107f32b51aad028607345a46c0975dd9b531421"}, "fast_tls": {:hex, :fast_tls, "1.1.13", "828cdc75e1e8fce8158846d2b971d8b4fe2b2ddcc75b759e88d751079bf78afd", [:rebar3], [{:p1_utils, "1.0.23", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "d1f422af40c7777fe534496f508ee86515cb929ad10f7d1d56aa94ce899b44a0"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, - "finch": {:hex, :finch, "0.16.0", "40733f02c89f94a112518071c0a91fe86069560f5dbdb39f9150042f44dcfb1a", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f660174c4d519e5fec629016054d60edd822cdfe2b7270836739ac2f97735ec5"}, + "finch": {:hex, :finch, "0.17.0", "17d06e1d44d891d20dbd437335eebe844e2426a0cd7e3a3e220b461127c73f70", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "8d014a661bb6a437263d4b5abf0bcbd3cf0deb26b1e8596f2a271d22e48934c7"}, "hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"}, "heap": {:hex, :heap, "2.0.2", "d98cb178286cfeb5edbcf17785e2d20af73ca57b5a2cf4af584118afbcf917eb", [:mix], [], "hexpm", "ba9ea2fe99eb4bcbd9a8a28eaf71cbcac449ca1d8e71731596aace9028c9d429"}, "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"}, @@ -58,6 +58,7 @@ "membrane_opentelemetry": {:hex, :membrane_opentelemetry, "0.1.0", "af774bc5b9bad3a822e9a26d8530819b0291b569a282c65a7dd51cc498e6e9cd", [:mix], [{:opentelemetry_api, "~> 1.0.0", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}], "hexpm", "2e4072a5f14eb95514701e242a7667a7178dfc6afd313d4643ec0726391c243b"}, "membrane_opus_format": {:hex, :membrane_opus_format, "0.3.0", "3804d9916058b7cfa2baa0131a644d8186198d64f52d592ae09e0942513cb4c2", [:mix], [], "hexpm", "8fc89c97be50de23ded15f2050fe603dcce732566fe6fdd15a2de01cb6b81afe"}, "membrane_opus_plugin": {:hex, :membrane_opus_plugin, "0.19.0", "9b16a047eb4b10224d82ea7b1fbc88a47ae9e246cc371f695b8ba579f48add4b", [:mix], [{:bunch, "~> 1.3", [hex: :bunch, repo: "hexpm", optional: false]}, {:bundlex, "~> 1.2", [hex: :bundlex, repo: "hexpm", optional: false]}, {:membrane_common_c, "~> 0.16.0", [hex: :membrane_common_c, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_opus_format, "~> 0.3.0", [hex: :membrane_opus_format, repo: "hexpm", optional: false]}, {:membrane_raw_audio_format, "~> 0.12.0", [hex: :membrane_raw_audio_format, repo: "hexpm", optional: false]}, {:unifex, "~> 1.0", [hex: :unifex, repo: "hexpm", optional: false]}], "hexpm", "79d42c0a0794132950f3b973e11ecbbdf5b3e5bf9dcdde177e50ec5e71a475d2"}, + "membrane_precompiled_dependency_provider": {:hex, :membrane_precompiled_dependency_provider, "0.1.1", "a0d5b7942f8be452c30744207f78284f6a0e0c84c968aba7d76e206fbf75bc5d", [:mix], [{:bundlex, "~> 1.4", [hex: :bundlex, repo: "hexpm", optional: false]}], "hexpm", "87ad44752e2cf0fa3b31c5aac15b863343c2f6e0f0fd201f5ec4c0bcda8c6fa3"}, "membrane_raw_audio_format": {:hex, :membrane_raw_audio_format, "0.12.0", "b574cd90f69ce2a8b6201b0ccf0826ca28b0fbc8245b8078d9f11cef65f7d5d5", [:mix], [{:bimap, "~> 1.1", [hex: :bimap, repo: "hexpm", optional: false]}, {:bunch, "~> 1.0", [hex: :bunch, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}], "hexpm", "6e6c98e3622a2b9df19eab50ba65d7eb45949b1ba306fa8423df6cdb12fd0b44"}, "membrane_raw_video_format": {:hex, :membrane_raw_video_format, "0.3.0", "ba10f475e0814a6fe79602a74536b796047577c7ef5b0e33def27cd344229699", [:mix], [], "hexpm", "2f08760061c8a5386ecf04273480f10e48d25a1a40aa99476302b0bcd34ccb1c"}, "membrane_realtimer_plugin": {:hex, :membrane_realtimer_plugin, "0.9.0", "27210d5e32a5e8bfd101c41e4d8c1876e873a52cc129ebfbee4d0ccbea1cbd21", [:mix], [{:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}], "hexpm", "b2e96d62135ee57ef9a5fdea94b3a9ab1198e5ea8ee248391b89c671125d1b51"}, @@ -81,10 +82,10 @@ "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, - "mint": {:hex, :mint, "1.5.1", "8db5239e56738552d85af398798c80648db0e90f343c8469f6c6d8898944fb6f", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "4a63e1e76a7c3956abd2c72f370a0d0aecddc3976dea5c27eccbecfa5e7d5b1e"}, + "mint": {:hex, :mint, "1.5.2", "4805e059f96028948870d23d7783613b7e6b0e2fb4e98d720383852a760067fd", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "d77d9e9ce4eb35941907f1d3df38d8f750c357865353e21d335bdcdf6d892a02"}, "mockery": {:hex, :mockery, "2.3.1", "a02fd60b10ac9ed37a7a2ecf6786c1f1dd5c75d2b079a60594b089fba32dc087", [:mix], [], "hexpm", "1d0971d88ebf084e962da3f2cfee16f0ea8e04ff73a7710428500d4500b947fa"}, "mox": {:hex, :mox, "1.1.0", "0f5e399649ce9ab7602f72e718305c0f9cdc351190f72844599545e4996af73c", [:mix], [], "hexpm", "d44474c50be02d5b72131070281a5d3895c0e7a95c780e90bc0cfe712f633a13"}, - "nimble_options": {:hex, :nimble_options, "1.0.2", "92098a74df0072ff37d0c12ace58574d26880e522c22801437151a159392270e", [:mix], [], "hexpm", "fd12a8db2021036ce12a309f26f564ec367373265b53e25403f0ee697380f1b8"}, + "nimble_options": {:hex, :nimble_options, "1.1.0", "3b31a57ede9cb1502071fade751ab0c7b8dbe75a9a4c2b5bbb0943a690b63172", [:mix], [], "hexpm", "8bbbb3941af3ca9acc7835f5655ea062111c9c27bcac53e004460dfd19008a99"}, "nimble_pool": {:hex, :nimble_pool, "1.0.0", "5eb82705d138f4dd4423f69ceb19ac667b3b492ae570c9f5c900bb3d2f50a847", [:mix], [], "hexpm", "80be3b882d2d351882256087078e1b1952a28bf98d0a287be87e4a24a710b67a"}, "numbers": {:hex, :numbers, "5.2.4", "f123d5bb7f6acc366f8f445e10a32bd403c8469bdbce8ce049e1f0972b607080", [:mix], [{:coerce, "~> 1.0", [hex: :coerce, repo: "hexpm", optional: false]}, {:decimal, "~> 1.9 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "eeccf5c61d5f4922198395bf87a465b6f980b8b862dd22d28198c5e6fab38582"}, "open_api_spex": {:hex, :open_api_spex, "3.18.0", "f9952b6bc8a1bf14168f3754981b7c8d72d015112bfedf2588471dd602e1e715", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:ymlr, "~> 2.0 or ~> 3.0 or ~> 4.0", [hex: :ymlr, repo: "hexpm", optional: true]}], "hexpm", "37849887ab67efab052376401fac28c0974b273ffaecd98f4532455ca0886464"}, @@ -99,21 +100,21 @@ "phoenix_live_view": {:hex, :phoenix_live_view, "0.18.18", "1f38fbd7c363723f19aad1a04b5490ff3a178e37daaf6999594d5f34796c47fc", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a5810d0472f3189ede6d2a95bda7f31c6113156b91784a3426cb0ab6a6d85214"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"}, "phoenix_template": {:hex, :phoenix_template, "1.0.3", "32de561eefcefa951aead30a1f94f1b5f0379bc9e340bb5c667f65f1edfa4326", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "16f4b6588a4152f3cc057b9d0c0ba7e82ee23afa65543da535313ad8d25d8e2c"}, - "plug": {:hex, :plug, "1.15.2", "94cf1fa375526f30ff8770837cb804798e0045fd97185f0bb9e5fcd858c792a3", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "02731fa0c2dcb03d8d21a1d941bdbbe99c2946c0db098eee31008e04c6283615"}, + "plug": {:hex, :plug, "1.15.3", "712976f504418f6dff0a3e554c40d705a9bcf89a7ccef92fc6a5ef8f16a30a97", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "cc4365a3c010a56af402e0809208873d113e9c38c401cabd88027ef4f5c01fd2"}, "plug_cowboy": {:hex, :plug_cowboy, "2.6.1", "9a3bbfceeb65eff5f39dab529e5cd79137ac36e913c02067dba3963a26efe9b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "de36e1a21f451a18b790f37765db198075c25875c64834bcc82d90b309eb6613"}, "plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"}, "protobuf": {:hex, :protobuf, "0.12.0", "58c0dfea5f929b96b5aa54ec02b7130688f09d2de5ddc521d696eec2a015b223", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "75fa6cbf262062073dd51be44dd0ab940500e18386a6c4e87d5819a58964dc45"}, "qex": {:hex, :qex, "0.5.1", "0d82c0f008551d24fffb99d97f8299afcb8ea9cf99582b770bd004ed5af63fd6", [:mix], [], "hexpm", "935a39fdaf2445834b95951456559e9dc2063d0a055742c558a99987b38d6bab"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, "ratio": {:hex, :ratio, "3.0.2", "60a5976872a4dc3d873ecc57eed1738589e99d1094834b9c935b118231297cfb", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:numbers, "~> 5.2.0", [hex: :numbers, repo: "hexpm", optional: false]}], "hexpm", "3a13ed5a30ad0bfd7e4a86bf86d93d2b5a06f5904417d38d3f3ea6406cdfc7bb"}, - "req": {:hex, :req, "0.4.5", "2071bbedd280f107b9e33e1ddff2beb3991ec1ae06caa2cca2ab756393d8aca5", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.9", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "dd23e9c7303ddeb2dee09ff11ad8102cca019e38394456f265fb7b9655c64dd8"}, + "req": {:hex, :req, "0.4.8", "2b754a3925ddbf4ad78c56f30208ced6aefe111a7ea07fb56c23dccc13eb87ae", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.9", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "7146e51d52593bb7f20d00b5308a5d7d17d663d6e85cd071452b613a8277100c"}, "rustler": {:hex, :rustler, "0.26.0", "06a2773d453ee3e9109efda643cf2ae633dedea709e2455ac42b83637c9249bf", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:toml, "~> 0.6", [hex: :toml, repo: "hexpm", optional: false]}], "hexpm", "42961e9d2083d004d5a53e111ad1f0c347efd9a05cb2eb2ffa1d037cdc74db91"}, "shmex": {:hex, :shmex, "0.5.0", "7dc4fb1a8bd851085a652605d690bdd070628717864b442f53d3447326bcd3e8", [:mix], [{:bunch_native, "~> 0.5.0", [hex: :bunch_native, repo: "hexpm", optional: false]}, {:bundlex, "~> 1.0", [hex: :bundlex, repo: "hexpm", optional: false]}], "hexpm", "b67bb1e22734758397c84458dbb746519e28eac210423c267c7248e59fc97bdc"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, - "statistics": {:hex, :statistics, "0.6.2", "213dcedc2b3ae7fb775b5510ea9630c66d3c0019ea2f86d5096559853623a60d", [:mix], [], "hexpm", "329f1008dc4ad24430d94c04b52ff09d5fb435ab11f34360831f11eb0c391c17"}, + "statistics": {:hex, :statistics, "0.6.3", "7fb182e7c1cab2980e392c7efef7ce326539f081f9defda4099550e9c2c7cb0f", [:mix], [], "hexpm", "a43d87726d240205e9ef47f29650a6e3132b4e4061e05512f32fa8120784a8e0"}, "sweet_xml": {:hex, :sweet_xml, "0.7.4", "a8b7e1ce7ecd775c7e8a65d501bc2cd933bff3a9c41ab763f5105688ef485d08", [:mix], [], "hexpm", "e7c4b0bdbf460c928234951def54fe87edf1a170f6896675443279e2dbeba167"}, "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, - "telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"}, + "telemetry_metrics": {:hex, :telemetry_metrics, "0.6.2", "2caabe9344ec17eafe5403304771c3539f3b6e2f7fb6a6f602558c825d0d0bfb", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9b43db0dc33863930b9ef9d27137e78974756f5f198cae18409970ed6fa5b561"}, "telemetry_metrics_prometheus": {:hex, :telemetry_metrics_prometheus, "1.1.0", "1cc23e932c1ef9aa3b91db257ead31ea58d53229d407e059b29bb962c1505a13", [:mix], [{:plug_cowboy, "~> 2.1", [hex: :plug_cowboy, repo: "hexpm", optional: false]}, {:telemetry_metrics_prometheus_core, "~> 1.0", [hex: :telemetry_metrics_prometheus_core, repo: "hexpm", optional: false]}], "hexpm", "d43b3659b3244da44fe0275b717701542365d4519b79d9ce895b9719c1ce4d26"}, "telemetry_metrics_prometheus_core": {:hex, :telemetry_metrics_prometheus_core, "1.1.0", "4e15f6d7dbedb3a4e3aed2262b7e1407f166fcb9c30ca3f96635dfbbef99965c", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "0dd10e7fe8070095df063798f82709b0a1224c31b8baf6278b423898d591a069"}, "telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"}, @@ -124,5 +125,5 @@ "websock_adapter": {:hex, :websock_adapter, "0.5.5", "9dfeee8269b27e958a65b3e235b7e447769f66b5b5925385f5a569269164a210", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "4b977ba4a01918acbf77045ff88de7f6972c2a009213c515a445c48f224ffce9"}, "websockex": {:hex, :websockex, "0.4.3", "92b7905769c79c6480c02daacaca2ddd49de936d912976a4d3c923723b647bf0", [:mix], [], "hexpm", "95f2e7072b85a3a4cc385602d42115b73ce0b74a9121d0d6dbbf557645ac53e4"}, "ymlr": {:hex, :ymlr, "3.0.1", "c7b459262aa52cbfee5d324995ac1bff8c765983460b1a4bb792f0f4db392232", [:mix], [], "hexpm", "759ce05102f7cb741cc65148044443d330cc75c9abd0769d5735bbf522219309"}, - "zarex": {:hex, :zarex, "1.0.3", "a9e9527a1c31df7f39499819bd76ccb15b0b4e479eed5a4a40db9df7ad7db25c", [:mix], [], "hexpm", "4400a7d33bbf222383ce9a3d5ec9411798eb2b12e86c65ad8e6ac08d8116ca8b"}, + "zarex": {:hex, :zarex, "1.0.5", "58239e3ee5d75f343262bb4df5cf466555a1c689f920e5d3651a9333972f7c7e", [:mix], [], "hexpm", "9fb72ef0567c2b2742f5119a1ba8a24a2fabb21b8d09820aefbf3e592fa9a46a"}, } From cae69a95e1bf6d6cafc443cce2dd8f4433c1df78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Tue, 30 Jan 2024 09:48:53 +0100 Subject: [PATCH 06/21] Add peer metadata --- lib/jellyfish/event.ex | 69 +++++++++++- lib/jellyfish/peer/webrtc.ex | 1 - lib/jellyfish/room.ex | 72 ++++++++---- lib/jellyfish/webhook_notifier.ex | 4 +- lib/jellyfish_web/controllers/peer_json.ex | 3 +- .../jellyfish/server_notifications.pb.ex | 101 +++++++++++++++++ mix.exs | 7 +- mix.lock | 15 +-- .../component/file_component_test.exs | 9 +- .../integration/server_notification_test.exs | 103 ++++++++++++++++-- test/support/webhook_plug.ex | 3 +- 11 files changed, 331 insertions(+), 56 deletions(-) diff --git a/lib/jellyfish/event.ex b/lib/jellyfish/event.ex index f4c3886e..bd3c4f8d 100644 --- a/lib/jellyfish/event.ex +++ b/lib/jellyfish/event.ex @@ -10,11 +10,18 @@ defmodule Jellyfish.Event do PeerConnected, PeerCrashed, PeerDisconnected, + PeerMetadataUpdated, RoomCrashed, RoomCreated, - RoomDeleted + RoomDeleted, + Track, + TrackAdded, + TrackMetadataUpdated, + TrackRemoved } + alias Membrane.RTC.Engine.Message + @pubsub Jellyfish.PubSub @valid_topics [:server_notification, :metrics] @@ -59,6 +66,38 @@ defmodule Jellyfish.Event do defp to_proto_server_notification({:component_crashed, room_id, component_id}), do: {:component_crashed, %ComponentCrashed{room_id: room_id, component_id: component_id}} + defp to_proto_server_notification({:peer_metadata_updated, room_id, peer_id, metadata}), + do: + {:peer_metadata_updated, + %PeerMetadataUpdated{room_id: room_id, peer_id: peer_id, metadata: Jason.encode!(metadata)}} + + defp to_proto_server_notification({:track_added, room_id, endpoint_info, track_info}) do + {:track_added, + %TrackAdded{ + room_id: room_id, + endpoint_info: endpoint_info, + track: to_proto_track(track_info) + }} + end + + defp to_proto_server_notification({:track_removed, room_id, endpoint_info, track_info}) do + {:track_removed, + %TrackRemoved{ + room_id: room_id, + endpoint_info: endpoint_info, + track: to_proto_track(track_info) + }} + end + + defp to_proto_server_notification({:track_metadata_updated, room_id, endpoint_info, track_id}) do + {:track_metadata_updated, + %TrackMetadataUpdated{ + room_id: room_id, + endpoint_info: endpoint_info, + track: to_proto_track(track_id) + }} + end + defp to_proto_server_notification({:hls_playable, room_id, component_id}), do: {:hls_playable, %HlsPlayable{room_id: room_id, component_id: component_id}} @@ -67,4 +106,32 @@ defmodule Jellyfish.Event do defp to_proto_server_notification({:hls_upload_crashed, room_id}), do: {:hls_upload_crashed, %HlsUploadCrashed{room_id: room_id}} + + defp to_proto_track(%Jellyfish.Track{} = track) do + %Track{ + id: track.id, + type: to_proto_track_type(track.type), + encoding: to_proto_encoding(track.encoding), + metadata: Jason.encode!(track.metadata) + } + end + + defp to_proto_track(%type{} = track) + when type in [Message.TrackAdded, Message.TrackMetadataUpdated, Message.TrackRemoved] do + %Track{ + id: track.track_id, + type: to_proto_track_type(track.track_type), + encoding: to_proto_encoding(track.track_encoding), + metadata: Jason.encode!(track.track_metadata) + } + end + + defp to_proto_encoding(:H264), do: :ENCODING_H264 + defp to_proto_encoding(:VP8), do: :ENCODING_VP8 + defp to_proto_encoding(:OPUS), do: :ENCODING_OPUS + defp to_proto_encoding(_encoding), do: :ENCODING_UNSPECIFIED + + defp to_proto_track_type(:video), do: :TRACK_TYPE_VIDEO + defp to_proto_track_type(:audio), do: :TRACK_TYPE_AUDIO + defp to_proto_track_type(_type), do: :TRACK_TYPE_UNSPECIFIED end diff --git a/lib/jellyfish/peer/webrtc.ex b/lib/jellyfish/peer/webrtc.ex index 2f294695..20c72def 100644 --- a/lib/jellyfish/peer/webrtc.ex +++ b/lib/jellyfish/peer/webrtc.ex @@ -53,7 +53,6 @@ defmodule Jellyfish.Peer.WebRTC do handshake_opts: handshake_options, filter_codecs: filter_codecs, log_metadata: [peer_id: options.peer_id], - trace_context: nil, extensions: %{opus: Membrane.RTP.VAD}, webrtc_extensions: webrtc_extensions, simulcast_config: %SimulcastConfig{ diff --git a/lib/jellyfish/room.ex b/lib/jellyfish/room.ex index 21a36991..19a8d4d2 100644 --- a/lib/jellyfish/room.ex +++ b/lib/jellyfish/room.ex @@ -20,9 +20,9 @@ defmodule Jellyfish.Room do alias Membrane.RTC.Engine.Message.{ EndpointAdded, - EndpointMetadataUpdated, EndpointCrashed, EndpointMessage, + EndpointMetadataUpdated, EndpointRemoved, TrackAdded, TrackMetadataUpdated, @@ -306,6 +306,14 @@ defmodule Jellyfish.Room do {component, state} = pop_in(state, [:components, component_id]) :ok = Engine.remove_endpoint(state.engine_pid, component_id) + component.tracks + |> Map.values() + |> Enum.each( + &Event.broadcast_server_notification( + {:track_removed, state.id, {:component_id, component_id}, &1} + ) + ) + Logger.info("Removed component #{inspect(component_id)}") if component.type == HLS, do: on_hls_removal(state.id, component.properties) @@ -449,10 +457,16 @@ defmodule Jellyfish.Room do %EndpointMetadataUpdated{endpoint_id: endpoint_id, endpoint_metadata: metadata}, state ) - when endpoint_exists?(state, endpoint_id) do - endpoint_group = get_endpoint_group(state, endpoint_id) + when is_map_key(state.peers, endpoint_id) do + Logger.debug("Peer #{endpoint_id} metadata updated: #{metadata}") + Event.broadcast_server_notification({:peer_metadata_updated, state.id, endpoint_id, metadata}) - state = put_in(state, [endpoint_group, endpoint_id, :metadata], metadata) + state = put_in(state, [:peers, endpoint_id, :metadata], metadata) + {:noreply, state} + end + + @impl true + def handle_info(%EndpointMetadataUpdated{}, state) do {:noreply, state} end @@ -461,6 +475,12 @@ defmodule Jellyfish.Room do when endpoint_exists?(state, endpoint_id) do Logger.info("Endpoint #{endpoint_id} added track #{inspect(track_info)}") + endpoint_id_type = get_endpoint_id_type(state, endpoint_id) + + Event.broadcast_server_notification( + {:track_added, state.id, {endpoint_id_type, endpoint_id}, track_info} + ) + state = add_track(state, track_info) {:noreply, state} @@ -488,6 +508,12 @@ defmodule Jellyfish.Room do state track -> + endpoint_id_type = get_endpoint_id_type(state, endpoint_id) + + Event.broadcast_server_notification( + {:track_metadata_updated, state.id, {endpoint_id_type, endpoint_id}, track_info} + ) + track = %Track{track | metadata: track_info.track_metadata} put_in(state, access_path, track) end @@ -500,6 +526,12 @@ defmodule Jellyfish.Room do when endpoint_exists?(state, endpoint_id) do Logger.info("Endpoint #{endpoint_id} removed track #{inspect(track_info)}") + endpoint_id_type = get_endpoint_id_type(state, endpoint_id) + + Event.broadcast_server_notification( + {:track_added, state.id, {endpoint_id_type, endpoint_id}, track_info} + ) + state = remove_track(state, track_info) {:noreply, state} @@ -511,6 +543,11 @@ defmodule Jellyfish.Room do {:noreply, state} end + @impl true + def handle_info(%EndpointRemoved{}, state) do + {:noreply, state} + end + @impl true def handle_info(info, state) do Logger.warning("Received unexpected info: #{inspect(info)}") @@ -634,26 +671,6 @@ defmodule Jellyfish.Room do defp validate_hls_subscription(%{properties: %{subscribe_mode: :manual}}), do: :ok - defp update_with_track_metadata(state, tracks) do - Enum.reduce(tracks, state, fn engine_track, state -> - endpoint_group = get_endpoint_group(state, engine_track.origin) - access_path = [endpoint_group, engine_track.origin, :tracks, engine_track.id] - - case get_in(state, access_path) do - nil -> - Logger.warning( - "Unable to update track's metadata - track #{inspect(engine_track.id)} doesn't exist" - ) - - state - - track -> - track = %Track{track | metadata: engine_track.metadata} - put_in(state, access_path, track) - end - end) - end - defp get_endpoint_group(state, endpoint_id) when is_map_key(state.components, endpoint_id), do: :components @@ -674,4 +691,11 @@ defmodule Jellyfish.Room do endpoint_group = get_endpoint_group(state, track_info.endpoint_id) [endpoint_group, track_info.endpoint_id, :tracks, track_info.track_id] end + + defp get_endpoint_id_type(state, endpoint_id) do + case get_endpoint_group(state, endpoint_id) do + :peers -> :peer_id + :components -> :component_id + end + end end diff --git a/lib/jellyfish/webhook_notifier.ex b/lib/jellyfish/webhook_notifier.ex index 10e7f549..c2d083be 100644 --- a/lib/jellyfish/webhook_notifier.ex +++ b/lib/jellyfish/webhook_notifier.ex @@ -50,8 +50,8 @@ defmodule Jellyfish.WebhookNotifier do defp send_webhook_notification(notification, webhook_url) when not is_nil(webhook_url) do case HTTPoison.post( webhook_url, - Jason.encode!(%{notification: notification}), - [{"Content-Type", "application/json"}] + notification, + [{"Content-Type", "application/octet-stream"}] ) do {:ok, result} when result.status_code >= 200 and result.status_code < 300 -> nil diff --git a/lib/jellyfish_web/controllers/peer_json.ex b/lib/jellyfish_web/controllers/peer_json.ex index 6ebf47c1..f4f87397 100644 --- a/lib/jellyfish_web/controllers/peer_json.ex +++ b/lib/jellyfish_web/controllers/peer_json.ex @@ -20,7 +20,8 @@ defmodule JellyfishWeb.PeerJSON do id: peer.id, type: type, status: "#{peer.status}", - tracks: peer.tracks |> Map.values() |> Enum.map(&Map.from_struct/1) + tracks: peer.tracks |> Map.values() |> Enum.map(&Map.from_struct/1), + metadata: peer.metadata } end end diff --git a/lib/protos/jellyfish/server_notifications.pb.ex b/lib/protos/jellyfish/server_notifications.pb.ex index 2dc99ad9..62919cf6 100644 --- a/lib/protos/jellyfish/server_notifications.pb.ex +++ b/lib/protos/jellyfish/server_notifications.pb.ex @@ -8,6 +8,27 @@ defmodule Jellyfish.ServerMessage.EventType do field :EVENT_TYPE_METRICS, 2 end +defmodule Jellyfish.ServerMessage.Encoding do + @moduledoc false + + use Protobuf, enum: true, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" + + field :ENCODING_UNSPECIFIED, 0 + field :ENCODING_H264, 1 + field :ENCODING_VP8, 2 + field :ENCODING_OPUS, 3 +end + +defmodule Jellyfish.ServerMessage.TrackType do + @moduledoc false + + use Protobuf, enum: true, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" + + field :TRACK_TYPE_UNSPECIFIED, 0 + field :TRACK_TYPE_VIDEO, 1 + field :TRACK_TYPE_AUDIO, 2 +end + defmodule Jellyfish.ServerMessage.RoomCrashed do @moduledoc false @@ -137,6 +158,66 @@ defmodule Jellyfish.ServerMessage.HlsUploadCrashed do field :room_id, 1, type: :string, json_name: "roomId" end +defmodule Jellyfish.ServerMessage.PeerMetadataUpdated do + @moduledoc false + + use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" + + field :room_id, 1, type: :string, json_name: "roomId" + field :peer_id, 2, type: :string, json_name: "peerId" + field :metadata, 3, type: :string +end + +defmodule Jellyfish.ServerMessage.Track do + @moduledoc false + + use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" + + field :id, 1, type: :string + field :type, 2, type: Jellyfish.ServerMessage.TrackType, enum: true + field :encoding, 3, type: Jellyfish.ServerMessage.Encoding, enum: true + field :metadata, 4, type: :string +end + +defmodule Jellyfish.ServerMessage.TrackAdded do + @moduledoc false + + use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" + + oneof :endpoint_info, 0 + + field :room_id, 1, type: :string, json_name: "roomId" + field :peer_id, 2, type: :string, json_name: "peerId", oneof: 0 + field :component_id, 3, type: :string, json_name: "componentId", oneof: 0 + field :track, 4, type: Jellyfish.ServerMessage.Track +end + +defmodule Jellyfish.ServerMessage.TrackRemoved do + @moduledoc false + + use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" + + oneof :endpoint_info, 0 + + field :room_id, 1, type: :string, json_name: "roomId" + field :peer_id, 2, type: :string, json_name: "peerId", oneof: 0 + field :component_id, 3, type: :string, json_name: "componentId", oneof: 0 + field :track, 4, type: Jellyfish.ServerMessage.Track +end + +defmodule Jellyfish.ServerMessage.TrackMetadataUpdated do + @moduledoc false + + use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" + + oneof :endpoint_info, 0 + + field :room_id, 1, type: :string, json_name: "roomId" + field :peer_id, 2, type: :string, json_name: "peerId", oneof: 0 + field :component_id, 3, type: :string, json_name: "componentId", oneof: 0 + field :track, 4, type: Jellyfish.ServerMessage.Track +end + defmodule Jellyfish.ServerMessage do @moduledoc false @@ -215,4 +296,24 @@ defmodule Jellyfish.ServerMessage do type: Jellyfish.ServerMessage.HlsUploadCrashed, json_name: "hlsUploadCrashed", oneof: 0 + + field :peer_metadata_updated, 16, + type: Jellyfish.ServerMessage.PeerMetadataUpdated, + json_name: "peerMetadataUpdated", + oneof: 0 + + field :track_added, 17, + type: Jellyfish.ServerMessage.TrackAdded, + json_name: "trackAdded", + oneof: 0 + + field :track_removed, 18, + type: Jellyfish.ServerMessage.TrackRemoved, + json_name: "trackRemoved", + oneof: 0 + + field :track_metadata_updated, 19, + type: Jellyfish.ServerMessage.TrackMetadataUpdated, + json_name: "trackMetadataUpdated", + oneof: 0 end diff --git a/mix.exs b/mix.exs index 7b79200b..82bfda35 100644 --- a/mix.exs +++ b/mix.exs @@ -69,12 +69,13 @@ defmodule Jellyfish.MixProject do # Membrane deps {:membrane_rtc_engine, path: "../membrane_rtc_engine/engine", override: true}, - {:membrane_rtc_engine_webrtc, "~> 0.5.0"}, + {:membrane_rtc_engine_webrtc, path: "../membrane_rtc_engine/webrtc", override: true}, {:membrane_rtc_engine_hls, "~> 0.4.0"}, {:membrane_rtc_engine_rtsp, "~> 0.4.0"}, - {:membrane_rtc_engine_file, "~> 0.2.0"}, - {:membrane_ice_plugin, "~> 0.17.0"}, + {:membrane_rtc_engine_file, path: "../membrane_rtc_engine/file", override: true}, + {:membrane_ice_plugin, "~> 0.18.0", override: true}, {:membrane_telemetry_metrics, "~> 0.1.0"}, + {:opentelemetry, "~> 1.3"}, # HLS endpoints deps {:membrane_audio_mix_plugin, "~> 0.16.0"}, diff --git a/mix.lock b/mix.lock index 9587ce47..f0670ca8 100644 --- a/mix.lock +++ b/mix.lock @@ -16,7 +16,7 @@ "credo": {:hex, :credo, "1.7.1", "6e26bbcc9e22eefbff7e43188e69924e78818e2fe6282487d0703652bc20fd62", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "e9871c6095a4c0381c89b6aa98bc6260a8ba6addccf7f6a53da8849c748a58a2"}, "dialyxir": {:hex, :dialyxir, "1.4.2", "764a6e8e7a354f0ba95d58418178d486065ead1f69ad89782817c296d0d746a5", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "516603d8067b2fd585319e4b13d3674ad4f314a5902ba8130cd97dc902ce6bbd"}, "divo": {:hex, :divo, "1.3.2", "3a5ce880a1fe930ea804361d1b57b5144129e79e1c856623d923a6fab6d539a1", [:mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:patiently, "~> 0.2", [hex: :patiently, repo: "hexpm", optional: false]}], "hexpm", "4bd035510838959709db2cacd28edd2eda7948d0e7f1b0dfa810a134c913a88a"}, - "elixir_make": {:hex, :elixir_make, "0.7.7", "7128c60c2476019ed978210c245badf08b03dbec4f24d05790ef791da11aa17c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5bc19fff950fad52bbe5f211b12db9ec82c6b34a9647da0c2224b8b8464c7e6c"}, + "elixir_make": {:hex, :elixir_make, "0.7.8", "505026f266552ee5aabca0b9f9c229cbb496c689537c9f922f3eb5431157efc7", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.0", [hex: :certifi, repo: "hexpm", optional: true]}], "hexpm", "7a71945b913d37ea89b06966e1342c85cfe549b15e6d6d081e8081c493062c07"}, "elixir_uuid": {:hex, :elixir_uuid, "1.2.1", "dce506597acb7e6b0daeaff52ff6a9043f5919a4c3315abb4143f0b00378c097", [:mix], [], "hexpm", "f7eba2ea6c3555cea09706492716b0d87397b88946e6380898c2889d68585752"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, "ex_aws": {:hex, :ex_aws, "2.5.0", "1785e69350b16514c1049330537c7da10039b1a53e1d253bbd703b135174aec3", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8 or ~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:mime, "~> 1.2 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "971b86e5495fc0ae1c318e35e23f389e74cf322f2c02d34037c6fc6d405006f1"}, @@ -48,16 +48,16 @@ "membrane_funnel_plugin": {:hex, :membrane_funnel_plugin, "0.9.0", "9cfe09e44d65751f7d9d8d3c42e14797f7be69e793ac112ea63cd224af70a7bf", [:mix], [{:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}], "hexpm", "988790aca59d453a6115109f050699f7f45a2eb6a7f8dc5c96392760cddead54"}, "membrane_h264_ffmpeg_plugin": {:hex, :membrane_h264_ffmpeg_plugin, "0.31.3", "f2117d3df369546d8c81107a47fc235b264a72d52a7a221ce06ba16d811648fa", [:mix], [{:bunch, "~> 1.6", [hex: :bunch, repo: "hexpm", optional: false]}, {:bundlex, "~> 1.3", [hex: :bundlex, repo: "hexpm", optional: false]}, {:membrane_common_c, "~> 0.16.0", [hex: :membrane_common_c, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_h264_format, "~> 0.6.1", [hex: :membrane_h264_format, repo: "hexpm", optional: false]}, {:membrane_raw_video_format, "~> 0.3.0", [hex: :membrane_raw_video_format, repo: "hexpm", optional: false]}, {:ratio, "~> 3.0", [hex: :ratio, repo: "hexpm", optional: false]}, {:unifex, "~> 1.1.0", [hex: :unifex, repo: "hexpm", optional: false]}], "hexpm", "ed8bf714e1320ad6d4b77e2f2892d8722915d0ca3973ee3e1b6aca5ee6ebaa94"}, "membrane_h264_format": {:hex, :membrane_h264_format, "0.6.1", "44836cd9de0abe989b146df1e114507787efc0cf0da2368f17a10c47b4e0738c", [:mix], [], "hexpm", "4b79be56465a876d2eac2c3af99e115374bbdc03eb1dea4f696ee9a8033cd4b0"}, - "membrane_h264_plugin": {:hex, :membrane_h264_plugin, "0.9.0", "4b76079489451794c27993fbe6108f10a34068d3034985dc73d601e46266ef90", [:mix], [{:bunch, "~> 1.4", [hex: :bunch, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_h264_format, "~> 0.6.0", [hex: :membrane_h264_format, repo: "hexpm", optional: false]}], "hexpm", "7ecb9fdbe26304a577d9e32895aeee963b0a4bcc01fd77ecd9aebabdafbce58d"}, + "membrane_h264_plugin": {:hex, :membrane_h264_plugin, "0.9.1", "ea140ab1ca21c528563675fdd7e14c80607e120e320dc930cac3dcfb4db3fc2b", [:mix], [{:bunch, "~> 1.4", [hex: :bunch, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_h264_format, "~> 0.6.0", [hex: :membrane_h264_format, repo: "hexpm", optional: false]}], "hexpm", "8f10db817e691fc1234ed85fe674b3f8718d3a410e4582736dcdd53664cae725"}, "membrane_h265_format": {:hex, :membrane_h265_format, "0.2.0", "1903c072cf7b0980c4d0c117ab61a2cd33e88782b696290de29570a7fab34819", [:mix], [], "hexpm", "6df418bdf242c0d9f7dbf2e5aea4c2d182e34ac9ad5a8b8cef2610c290002e83"}, "membrane_http_adaptive_stream_plugin": {:hex, :membrane_http_adaptive_stream_plugin, "0.18.0", "c83dd7e921dfd595b10e12d85bde313612ece8ca64d6ff27815156b900592d16", [:mix], [{:bunch, "~> 1.6", [hex: :bunch, repo: "hexpm", optional: false]}, {:membrane_aac_plugin, "~> 0.18.0", [hex: :membrane_aac_plugin, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_h264_plugin, "~> 0.9.0", [hex: :membrane_h264_plugin, repo: "hexpm", optional: false]}, {:membrane_mp4_plugin, "~> 0.31.0", [hex: :membrane_mp4_plugin, repo: "hexpm", optional: false]}, {:membrane_tee_plugin, "~> 0.12.0", [hex: :membrane_tee_plugin, repo: "hexpm", optional: false]}, {:qex, "~> 0.5", [hex: :qex, repo: "hexpm", optional: false]}], "hexpm", "4e3a1ec9e84892d6f0b115183f4e4f3e202fcefe07aa722f7c2b107cd4403669"}, - "membrane_ice_plugin": {:hex, :membrane_ice_plugin, "0.17.0", "1299689e2ee36f4083e84e7ddd27f1333d3b92662fef9f47cdcb8158903be6e2", [:mix], [{:bunch, "~> 1.5", [hex: :bunch, repo: "hexpm", optional: false]}, {:ex_dtls, "~> 0.12.0", [hex: :ex_dtls, repo: "hexpm", optional: false]}, {:fake_turn, "~> 0.4.0", [hex: :fake_turn, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_funnel_plugin, "~> 0.9.0", [hex: :membrane_funnel_plugin, repo: "hexpm", optional: false]}, {:membrane_opentelemetry, "~> 0.1.0", [hex: :membrane_opentelemetry, repo: "hexpm", optional: false]}, {:membrane_rtp_format, "~> 0.8.0", [hex: :membrane_rtp_format, repo: "hexpm", optional: false]}, {:membrane_telemetry_metrics, "~> 0.1.0", [hex: :membrane_telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "837ee99f53fe2097acea0d908c3afd572524e93bfb3e2895fe23ed3c906a5382"}, + "membrane_ice_plugin": {:hex, :membrane_ice_plugin, "0.18.0", "beecb741b641b0c8b4efea0569fa68a3564051294e3ed10a10a1e29028e1d474", [:mix], [{:bunch, "~> 1.5", [hex: :bunch, repo: "hexpm", optional: false]}, {:ex_dtls, "~> 0.12.0", [hex: :ex_dtls, repo: "hexpm", optional: false]}, {:fake_turn, "~> 0.4.0", [hex: :fake_turn, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_funnel_plugin, "~> 0.9.0", [hex: :membrane_funnel_plugin, repo: "hexpm", optional: false]}, {:membrane_rtp_format, "~> 0.8.0", [hex: :membrane_rtp_format, repo: "hexpm", optional: false]}, {:membrane_telemetry_metrics, "~> 0.1.0", [hex: :membrane_telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "fff74d447d42902bb014bc8cdc78d6da3f797b59ed8fd622bfc7c6854323a287"}, "membrane_mp4_format": {:hex, :membrane_mp4_format, "0.8.0", "8c6e7d68829228117d333b4fbb030e7be829aab49dd8cb047fdc664db1812e6a", [:mix], [], "hexpm", "148dea678a1f82ccfd44dbde6f936d2f21255f496cb45a22cc6eec427f025522"}, "membrane_mp4_plugin": {:hex, :membrane_mp4_plugin, "0.31.0", "1932c86e2f4a24aca1b99ee531a131fd0da1128db8975ba8f8738e3b1bbcfabd", [:mix], [{:bunch, "~> 1.5", [hex: :bunch, repo: "hexpm", optional: false]}, {:membrane_aac_format, "~> 0.8.0", [hex: :membrane_aac_format, repo: "hexpm", optional: false]}, {:membrane_cmaf_format, "~> 0.7.0", [hex: :membrane_cmaf_format, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_file_plugin, "~> 0.16.0", [hex: :membrane_file_plugin, repo: "hexpm", optional: false]}, {:membrane_h264_format, "~> 0.6.1", [hex: :membrane_h264_format, repo: "hexpm", optional: false]}, {:membrane_h264_plugin, "~> 0.9.0", [hex: :membrane_h264_plugin, repo: "hexpm", optional: false]}, {:membrane_h265_format, "~> 0.2.0", [hex: :membrane_h265_format, repo: "hexpm", optional: false]}, {:membrane_mp4_format, "~> 0.8.0", [hex: :membrane_mp4_format, repo: "hexpm", optional: false]}, {:membrane_opus_format, "~> 0.3.0", [hex: :membrane_opus_format, repo: "hexpm", optional: false]}], "hexpm", "9968e56e02085228974bf6a59c8858f3c0d9800a4e767c1b3b2f2890050c72f4"}, "membrane_ogg_plugin": {:hex, :membrane_ogg_plugin, "0.3.0", "6e98b8932a2b88174dc3922989a475e02ee327589222b1c8422ff4fa630325c3", [:mix], [{:crc, "~> 0.10", [hex: :crc, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_opus_format, "~> 0.3.0", [hex: :membrane_opus_format, repo: "hexpm", optional: false]}], "hexpm", "82557299b3d72aab0fafa07a05dcc3a5a842eeaa3de3f2f3959677517b66b713"}, "membrane_opentelemetry": {:hex, :membrane_opentelemetry, "0.1.0", "af774bc5b9bad3a822e9a26d8530819b0291b569a282c65a7dd51cc498e6e9cd", [:mix], [{:opentelemetry_api, "~> 1.0.0", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}], "hexpm", "2e4072a5f14eb95514701e242a7667a7178dfc6afd313d4643ec0726391c243b"}, "membrane_opus_format": {:hex, :membrane_opus_format, "0.3.0", "3804d9916058b7cfa2baa0131a644d8186198d64f52d592ae09e0942513cb4c2", [:mix], [], "hexpm", "8fc89c97be50de23ded15f2050fe603dcce732566fe6fdd15a2de01cb6b81afe"}, - "membrane_opus_plugin": {:hex, :membrane_opus_plugin, "0.19.0", "9b16a047eb4b10224d82ea7b1fbc88a47ae9e246cc371f695b8ba579f48add4b", [:mix], [{:bunch, "~> 1.3", [hex: :bunch, repo: "hexpm", optional: false]}, {:bundlex, "~> 1.2", [hex: :bundlex, repo: "hexpm", optional: false]}, {:membrane_common_c, "~> 0.16.0", [hex: :membrane_common_c, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_opus_format, "~> 0.3.0", [hex: :membrane_opus_format, repo: "hexpm", optional: false]}, {:membrane_raw_audio_format, "~> 0.12.0", [hex: :membrane_raw_audio_format, repo: "hexpm", optional: false]}, {:unifex, "~> 1.0", [hex: :unifex, repo: "hexpm", optional: false]}], "hexpm", "79d42c0a0794132950f3b973e11ecbbdf5b3e5bf9dcdde177e50ec5e71a475d2"}, + "membrane_opus_plugin": {:hex, :membrane_opus_plugin, "0.19.1", "1e98f01226eed8d1483b606728c399baeac9cf3d19ac101e5f095666932f1994", [:mix], [{:bunch, "~> 1.3", [hex: :bunch, repo: "hexpm", optional: false]}, {:bundlex, "~> 1.2", [hex: :bundlex, repo: "hexpm", optional: false]}, {:membrane_common_c, "~> 0.16.0", [hex: :membrane_common_c, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_opus_format, "~> 0.3.0", [hex: :membrane_opus_format, repo: "hexpm", optional: false]}, {:membrane_precompiled_dependency_provider, "~> 0.1.0", [hex: :membrane_precompiled_dependency_provider, repo: "hexpm", optional: false]}, {:membrane_raw_audio_format, "~> 0.12.0", [hex: :membrane_raw_audio_format, repo: "hexpm", optional: false]}, {:unifex, "~> 1.0", [hex: :unifex, repo: "hexpm", optional: false]}], "hexpm", "55e4c17a2d9bb8c196b549c3cbb075121beac591ce56d36f76d80a08ecf79d7d"}, "membrane_precompiled_dependency_provider": {:hex, :membrane_precompiled_dependency_provider, "0.1.1", "a0d5b7942f8be452c30744207f78284f6a0e0c84c968aba7d76e206fbf75bc5d", [:mix], [{:bundlex, "~> 1.4", [hex: :bundlex, repo: "hexpm", optional: false]}], "hexpm", "87ad44752e2cf0fa3b31c5aac15b863343c2f6e0f0fd201f5ec4c0bcda8c6fa3"}, "membrane_raw_audio_format": {:hex, :membrane_raw_audio_format, "0.12.0", "b574cd90f69ce2a8b6201b0ccf0826ca28b0fbc8245b8078d9f11cef65f7d5d5", [:mix], [{:bimap, "~> 1.1", [hex: :bimap, repo: "hexpm", optional: false]}, {:bunch, "~> 1.0", [hex: :bunch, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}], "hexpm", "6e6c98e3622a2b9df19eab50ba65d7eb45949b1ba306fa8423df6cdb12fd0b44"}, "membrane_raw_video_format": {:hex, :membrane_raw_video_format, "0.3.0", "ba10f475e0814a6fe79602a74536b796047577c7ef5b0e33def27cd344229699", [:mix], [], "hexpm", "2f08760061c8a5386ecf04273480f10e48d25a1a40aa99476302b0bcd34ccb1c"}, @@ -78,7 +78,7 @@ "membrane_udp_plugin": {:hex, :membrane_udp_plugin, "0.12.0", "f3930a592f975f5aef924ff70b1072e55451de16ec5dce7dd264ecf9d034b9ad", [:mix], [{:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:mockery, "~> 2.3.0", [hex: :mockery, repo: "hexpm", optional: false]}], "hexpm", "65e846f7523e443215b6954136971d4f00a8e8f375ef015153daa535ce607769"}, "membrane_video_compositor_plugin": {:hex, :membrane_video_compositor_plugin, "0.7.0", "2273743fd0a47660880276e0bbb8a9f8848e09b05b425101d1cc0c5d245ff8ea", [:mix], [{:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_framerate_converter_plugin, "~> 0.8.0", [hex: :membrane_framerate_converter_plugin, repo: "hexpm", optional: false]}, {:membrane_raw_video_format, "~> 0.3.0", [hex: :membrane_raw_video_format, repo: "hexpm", optional: false]}, {:qex, "~> 0.5.1", [hex: :qex, repo: "hexpm", optional: false]}, {:ratio, "~> 3.0", [hex: :ratio, repo: "hexpm", optional: false]}, {:rustler, "~> 0.26.0", [hex: :rustler, repo: "hexpm", optional: false]}, {:unifex, "~> 1.0", [hex: :unifex, repo: "hexpm", optional: false]}], "hexpm", "68ea6a5770cf053464d6fa009a20f85ca559267f5a454370506c6d40965985de"}, "membrane_vp8_format": {:hex, :membrane_vp8_format, "0.4.0", "6c29ec67479edfbab27b11266dc92f18f3baf4421262c5c31af348c33e5b92c7", [:mix], [], "hexpm", "8bb005ede61db8fcb3535a883f32168b251c2dfd1109197c8c3b39ce28ed08e2"}, - "membrane_webrtc_plugin": {:hex, :membrane_webrtc_plugin, "0.17.0", "631c01283a4534210ff8d29384260db350fe48d68276fb4db984d4f85738f4a1", [:mix], [{:bunch, "~> 1.5", [hex: :bunch, repo: "hexpm", optional: false]}, {:ex_libsrtp, ">= 0.0.0", [hex: :ex_libsrtp, repo: "hexpm", optional: false]}, {:ex_sdp, "~> 0.13.1", [hex: :ex_sdp, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_funnel_plugin, "~> 0.9.0", [hex: :membrane_funnel_plugin, repo: "hexpm", optional: false]}, {:membrane_h264_plugin, "~> 0.9.0", [hex: :membrane_h264_plugin, repo: "hexpm", optional: false]}, {:membrane_ice_plugin, "~> 0.17.0", [hex: :membrane_ice_plugin, repo: "hexpm", optional: false]}, {:membrane_opentelemetry, "~> 0.1.0", [hex: :membrane_opentelemetry, repo: "hexpm", optional: false]}, {:membrane_rtp_format, "~> 0.8.0", [hex: :membrane_rtp_format, repo: "hexpm", optional: false]}, {:membrane_rtp_h264_plugin, "~> 0.19.0", [hex: :membrane_rtp_h264_plugin, repo: "hexpm", optional: false]}, {:membrane_rtp_opus_plugin, ">= 0.9.0", [hex: :membrane_rtp_opus_plugin, repo: "hexpm", optional: false]}, {:membrane_rtp_plugin, "~> 0.24.0", [hex: :membrane_rtp_plugin, repo: "hexpm", optional: false]}, {:membrane_rtp_vp8_plugin, "~> 0.9.0", [hex: :membrane_rtp_vp8_plugin, repo: "hexpm", optional: false]}, {:opentelemetry, "~> 1.0.4", [hex: :opentelemetry, repo: "hexpm", optional: false]}, {:opentelemetry_api, "~> 1.0", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}, {:qex, "~> 0.5.0", [hex: :qex, repo: "hexpm", optional: false]}], "hexpm", "ec32d6318f2a6ad857b3056a8e60ac18894977a79f1b09fc31970dff067ff6a7"}, + "membrane_webrtc_plugin": {:hex, :membrane_webrtc_plugin, "0.18.0", "25e279b9aa39dc12a0aa65a93bf0b702f5ace93a9cf2f9e14fc1e99e5011c0d2", [:mix], [{:bunch, "~> 1.5", [hex: :bunch, repo: "hexpm", optional: false]}, {:ex_libsrtp, ">= 0.0.0", [hex: :ex_libsrtp, repo: "hexpm", optional: false]}, {:ex_sdp, "~> 0.13.1", [hex: :ex_sdp, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_funnel_plugin, "~> 0.9.0", [hex: :membrane_funnel_plugin, repo: "hexpm", optional: false]}, {:membrane_h264_plugin, "~> 0.9.0", [hex: :membrane_h264_plugin, repo: "hexpm", optional: false]}, {:membrane_ice_plugin, "~> 0.18.0", [hex: :membrane_ice_plugin, repo: "hexpm", optional: false]}, {:membrane_rtp_format, "~> 0.8.0", [hex: :membrane_rtp_format, repo: "hexpm", optional: false]}, {:membrane_rtp_h264_plugin, "~> 0.19.0", [hex: :membrane_rtp_h264_plugin, repo: "hexpm", optional: false]}, {:membrane_rtp_opus_plugin, ">= 0.9.0", [hex: :membrane_rtp_opus_plugin, repo: "hexpm", optional: false]}, {:membrane_rtp_plugin, "~> 0.24.0", [hex: :membrane_rtp_plugin, repo: "hexpm", optional: false]}, {:membrane_rtp_vp8_plugin, "~> 0.9.0", [hex: :membrane_rtp_vp8_plugin, repo: "hexpm", optional: false]}, {:qex, "~> 0.5.0", [hex: :qex, repo: "hexpm", optional: false]}], "hexpm", "00fede6ec021611d58c23b62c3d9311ea70a38444c459e7c5a6031dea9e217f1"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, @@ -89,8 +89,9 @@ "nimble_pool": {:hex, :nimble_pool, "1.0.0", "5eb82705d138f4dd4423f69ceb19ac667b3b492ae570c9f5c900bb3d2f50a847", [:mix], [], "hexpm", "80be3b882d2d351882256087078e1b1952a28bf98d0a287be87e4a24a710b67a"}, "numbers": {:hex, :numbers, "5.2.4", "f123d5bb7f6acc366f8f445e10a32bd403c8469bdbce8ce049e1f0972b607080", [:mix], [{:coerce, "~> 1.0", [hex: :coerce, repo: "hexpm", optional: false]}, {:decimal, "~> 1.9 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "eeccf5c61d5f4922198395bf87a465b6f980b8b862dd22d28198c5e6fab38582"}, "open_api_spex": {:hex, :open_api_spex, "3.18.0", "f9952b6bc8a1bf14168f3754981b7c8d72d015112bfedf2588471dd602e1e715", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:ymlr, "~> 2.0 or ~> 3.0 or ~> 4.0", [hex: :ymlr, repo: "hexpm", optional: true]}], "hexpm", "37849887ab67efab052376401fac28c0974b273ffaecd98f4532455ca0886464"}, - "opentelemetry": {:hex, :opentelemetry, "1.0.5", "f0cd36ac8b30b68e8d70cec5bb88801ed7f3fe79aac67597054ed5490542e810", [:rebar3], [{:opentelemetry_api, "~> 1.0", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}], "hexpm", "3b17f8933a58e1246f42a0c215840fd8218aebbcabdb0aac62b0c766fe85542e"}, - "opentelemetry_api": {:hex, :opentelemetry_api, "1.0.3", "77f9644c42340cd8b18c728cde4822ed55ae136f0d07761b78e8c54da46af93a", [:mix, :rebar3], [], "hexpm", "4293e06bd369bc004e6fad5edbb56456d891f14bd3f9f1772b18f1923e0678ea"}, + "opentelemetry": {:hex, :opentelemetry, "1.3.1", "f0a342a74379e3540a634e7047967733da4bc8b873ec9026e224b2bd7369b1fc", [:rebar3], [{:opentelemetry_api, "~> 1.2.2", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}, {:opentelemetry_semantic_conventions, "~> 0.2", [hex: :opentelemetry_semantic_conventions, repo: "hexpm", optional: false]}], "hexpm", "de476b2ac4faad3e3fe3d6e18b35dec9cb338c3b9910c2ce9317836dacad3483"}, + "opentelemetry_api": {:hex, :opentelemetry_api, "1.2.2", "693f47b0d8c76da2095fe858204cfd6350c27fe85d00e4b763deecc9588cf27a", [:mix, :rebar3], [{:opentelemetry_semantic_conventions, "~> 0.2", [hex: :opentelemetry_semantic_conventions, repo: "hexpm", optional: false]}], "hexpm", "dc77b9a00f137a858e60a852f14007bb66eda1ffbeb6c05d5fe6c9e678b05e9d"}, + "opentelemetry_semantic_conventions": {:hex, :opentelemetry_semantic_conventions, "0.2.0", "b67fe459c2938fcab341cb0951c44860c62347c005ace1b50f8402576f241435", [:mix, :rebar3], [], "hexpm", "d61fa1f5639ee8668d74b527e6806e0503efc55a42db7b5f39939d84c07d6895"}, "p1_utils": {:hex, :p1_utils, "1.0.23", "7f94466ada69bd982ea7bb80fbca18e7053e7d0b82c9d9e37621fa508587069b", [:rebar3], [], "hexpm", "47f21618694eeee5006af1c88731ad86b757161e7823c29b6f73921b571c8502"}, "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"}, "patiently": {:hex, :patiently, "0.2.0", "67eb139591e10c4b363ae0198e832552f191c58894731efd3bf124ec4722267a", [:mix], [], "hexpm", "c08cc5edc27def565647a9b55a0bea8025a5f81a4472e57692f28f2292c44c94"}, diff --git a/test/jellyfish_web/controllers/component/file_component_test.exs b/test/jellyfish_web/controllers/component/file_component_test.exs index 11815235..6d93411d 100644 --- a/test/jellyfish_web/controllers/component/file_component_test.exs +++ b/test/jellyfish_web/controllers/component/file_component_test.exs @@ -3,6 +3,7 @@ defmodule JellyfishWeb.Component.FileComponentTest do use JellyfishWeb.ComponentCase @file_component_directory "file_component_sources" + @fixtures_directory "test/fixtures" @video_source "video.h264" @audio_source "audio.ogg" @@ -14,13 +15,7 @@ defmodule JellyfishWeb.Component.FileComponentTest do File.mkdir_p!(media_sources_directory) - media_sources_directory - |> Path.join(@video_source) - |> File.touch!() - - media_sources_directory - |> Path.join(@audio_source) - |> File.touch!() + File.cp_r!(@fixtures_directory, media_sources_directory) on_exit(fn -> :file.del_dir_r(media_sources_directory) end) diff --git a/test/jellyfish_web/integration/server_notification_test.exs b/test/jellyfish_web/integration/server_notification_test.exs index b5fd04bf..a1c60422 100644 --- a/test/jellyfish_web/integration/server_notification_test.exs +++ b/test/jellyfish_web/integration/server_notification_test.exs @@ -20,11 +20,15 @@ defmodule JellyfishWeb.Integration.ServerNotificationTest do MetricsReport, PeerConnected, PeerDisconnected, + PeerMetadataUpdated, RoomCrashed, RoomCreated, RoomDeleted, SubscribeRequest, - SubscribeResponse + SubscribeResponse, + Track, + TrackAdded, + TrackRemoved } alias JellyfishWeb.{PeerSocket, ServerSocket, WS} @@ -37,6 +41,10 @@ defmodule JellyfishWeb.Integration.ServerNotificationTest do @auth_response %Authenticated{} @pubsub Jellyfish.PubSub + @file_component_directory "file_component_sources" + @fixtures_directory "test/fixtures" + @video_source "video.h264" + @max_peers 1 @source_uri "rtsp://placeholder-19inrifjbsjb.it:12345/afwefae" @@ -194,7 +202,7 @@ defmodule JellyfishWeb.Integration.ServerNotificationTest do end test "sends a message when peer connects and room is deleted", %{conn: conn} do - {room_id, peer_id, conn} = subscribe_on_notifications_and_connect_peer(conn) + {room_id, peer_id, conn, _ws} = subscribe_on_notifications_and_connect_peer(conn) _conn = delete(conn, ~p"/room/#{room_id}") assert_receive %RoomDeleted{room_id: ^room_id} @@ -209,7 +217,7 @@ defmodule JellyfishWeb.Integration.ServerNotificationTest do end test "sends a message when peer connects and peer is removed", %{conn: conn} do - {room_id, peer_id, conn} = subscribe_on_notifications_and_connect_peer(conn) + {room_id, peer_id, conn, _ws} = subscribe_on_notifications_and_connect_peer(conn) conn = delete(conn, ~p"/room/#{room_id}/peer/#{peer_id}") assert response(conn, :no_content) @@ -228,7 +236,7 @@ defmodule JellyfishWeb.Integration.ServerNotificationTest do end test "sends a message when peer connects and room crashes", %{conn: conn} do - {room_id, peer_id, _conn} = subscribe_on_notifications_and_connect_peer(conn) + {room_id, peer_id, _conn, _ws} = subscribe_on_notifications_and_connect_peer(conn) {:ok, room_pid} = Jellyfish.RoomService.find_room(room_id) Process.exit(room_pid, :kill) @@ -245,7 +253,7 @@ defmodule JellyfishWeb.Integration.ServerNotificationTest do end test "sends a message when peer connects and it crashes", %{conn: conn} do - {room_id, peer_id, conn} = subscribe_on_notifications_and_connect_peer(conn) + {room_id, peer_id, conn, _ws} = subscribe_on_notifications_and_connect_peer(conn) {:ok, room_pid} = Jellyfish.RoomService.find_room(room_id) @@ -264,12 +272,78 @@ defmodule JellyfishWeb.Integration.ServerNotificationTest do delete(conn, ~p"/room/#{room_id}") end + test "sends message when tracks are added or removed", %{conn: conn} do + media_sources_directory = + Application.fetch_env!(:jellyfish, :media_files_path) + |> Path.join(@file_component_directory) + |> Path.expand() + + File.mkdir_p!(media_sources_directory) + File.cp_r!(@fixtures_directory, media_sources_directory) + + {room_id, _peer_id, conn, _ws} = subscribe_on_notifications_and_connect_peer(conn) + {conn, id} = add_file_component(conn, room_id) + + assert_receive %TrackAdded{ + room_id: ^room_id, + endpoint_info: {:component_id, ^id}, + track: + %Track{ + id: _track_id, + type: :TRACK_TYPE_VIDEO, + encoding: :ENCODING_H264, + metadata: "null" + } = + track_info + } = track_added, + 500 + + assert_receive {:webhook_notification, ^track_added}, 1_000 + + _conn = delete(conn, ~p"/room/#{room_id}/component/#{id}") + + assert_receive %TrackRemoved{ + room_id: ^room_id, + endpoint_info: {:component_id, ^id}, + track: ^track_info + } = track_removed + + assert_receive {:webhook_notification, ^track_removed}, 1_000 + + :file.del_dir_r(media_sources_directory) + end + + test "sends message when peer metadata is updated", %{conn: conn} do + {room_id, peer_id, _conn, peer_ws} = subscribe_on_notifications_and_connect_peer(conn) + + metadata = %{name: "Jellyuser"} + metadata_encoded = Jason.encode!(metadata) + + media_event = %PeerMessage.MediaEvent{ + data: %{"type" => "connect", "data" => %{"metadata" => metadata}} |> Jason.encode!() + } + + :ok = + WS.send_binary_frame( + peer_ws, + PeerMessage.encode(%PeerMessage{content: {:media_event, media_event}}) + ) + + assert_receive %PeerMetadataUpdated{ + room_id: ^room_id, + peer_id: ^peer_id, + metadata: ^metadata_encoded + } = track_added + + assert_receive {:webhook_notification, ^track_added}, 1_000 + end + describe "hls upload" do setup :verify_on_exit! setup :set_mox_from_context test "sends a message when hls was uploaded", %{conn: conn} do - {room_id, _peer_id, _conn} = subscribe_on_notifications_and_connect_peer(conn) + {room_id, _peer_id, _conn, _ws} = subscribe_on_notifications_and_connect_peer(conn) test_hls_manager(room_id, request_no: 4, status_code: 200) assert_receive %HlsUploaded{room_id: ^room_id} @@ -277,7 +351,7 @@ defmodule JellyfishWeb.Integration.ServerNotificationTest do end test "sends a message when hls upload crashed", %{conn: conn} do - {room_id, _peer_id, _conn} = subscribe_on_notifications_and_connect_peer(conn) + {room_id, _peer_id, _conn, _ws} = subscribe_on_notifications_and_connect_peer(conn) test_hls_manager(room_id, request_no: 1, status_code: 400) assert_receive %HlsUploadCrashed{room_id: ^room_id} @@ -327,7 +401,7 @@ defmodule JellyfishWeb.Integration.ServerNotificationTest do assert_receive {:webhook_notification, %PeerConnected{peer_id: ^peer_id, room_id: ^room_id}}, 1_000 - {room_id, peer_id, conn} + {room_id, peer_id, conn, peer_ws} end def create_and_authenticate() do @@ -397,6 +471,19 @@ defmodule JellyfishWeb.Integration.ServerNotificationTest do {conn, id} end + defp add_file_component(conn, room_id) do + conn = + post(conn, ~p"/room/#{room_id}/component", + type: "file", + options: %{filePath: @video_source} + ) + + assert %{"id" => id, "properties" => %{"filePath" => @video_source}, "type" => "file"} = + json_response(conn, :created)["data"] + + {conn, id} + end + defp auth_request(token) do ServerMessage.encode(%ServerMessage{content: {:auth_request, %AuthRequest{token: token}}}) end diff --git a/test/support/webhook_plug.ex b/test/support/webhook_plug.ex index 502dad40..04e30fc9 100644 --- a/test/support/webhook_plug.ex +++ b/test/support/webhook_plug.ex @@ -14,10 +14,9 @@ defmodule WebHookPlug do def call(conn, _opts) do {:ok, body, conn} = Plug.Conn.read_body(conn, []) - notification = Jason.decode!(body) notification = - notification |> Map.get("notification") |> ServerMessage.decode() |> Map.get(:content) + body |> ServerMessage.decode() |> Map.get(:content) {_notification_type, notification} = notification From b6c7d95abc0297997a840e933c02ff0f2637d1dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Wed, 31 Jan 2024 13:08:38 +0100 Subject: [PATCH 07/21] Test for message in FileComponent test --- lib/jellyfish_web/api_spec/peer.ex | 18 ++++++- mix.exs | 18 ++++--- mix.lock | 18 +++---- openapi.yaml | 10 ++++ .../component/file_component_test.exs | 50 +++++++++++++++++++ .../integration/peer_socket_test.exs | 26 +++------- .../integration/server_notification_test.exs | 50 +++---------------- test/support/ws.ex | 46 +++++++++++++++++ 8 files changed, 157 insertions(+), 79 deletions(-) diff --git a/lib/jellyfish_web/api_spec/peer.ex b/lib/jellyfish_web/api_spec/peer.ex index fdf37aa3..a44a63fd 100644 --- a/lib/jellyfish_web/api_spec/peer.ex +++ b/lib/jellyfish_web/api_spec/peer.ex @@ -61,6 +61,19 @@ defmodule JellyfishWeb.ApiSpec.Peer do }) end + defmodule PeerMetadata do + @moduledoc false + + require OpenApiSpex + + OpenApiSpex.schema(%{ + title: "PeerMetadata", + description: "Custom metadata set by the peer", + example: %{name: "JellyfishUser"}, + nullable: true + }) + end + OpenApiSpex.schema(%{ title: "Peer", description: "Describes peer status", @@ -73,8 +86,9 @@ defmodule JellyfishWeb.ApiSpec.Peer do type: :array, items: JellyfishWeb.ApiSpec.Track, description: "List of all peer's tracks" - } + }, + metadata: PeerMetadata }, - required: [:id, :type, :status, :tracks] + required: [:id, :type, :status, :tracks, :metadata] }) end diff --git a/mix.exs b/mix.exs index 82bfda35..29040dd2 100644 --- a/mix.exs +++ b/mix.exs @@ -68,14 +68,20 @@ defmodule Jellyfish.MixProject do {:protobuf, "~> 0.12.0"}, # Membrane deps - {:membrane_rtc_engine, path: "../membrane_rtc_engine/engine", override: true}, - {:membrane_rtc_engine_webrtc, path: "../membrane_rtc_engine/webrtc", override: true}, - {:membrane_rtc_engine_hls, "~> 0.4.0"}, + {:membrane_rtc_engine, + github: "jellyfish-dev/membrane_rtc_engine", + branch: "RTC-435-track-metadata", + sparse: "engine", + override: true}, + {:membrane_rtc_engine_webrtc, + github: "jellyfish-dev/membrane_rtc_engine", sparse: "webrtc", override: true}, + {:membrane_rtc_engine_hls, + github: "jellyfish-dev/membrane_rtc_engine", sparse: "hls", override: true}, {:membrane_rtc_engine_rtsp, "~> 0.4.0"}, - {:membrane_rtc_engine_file, path: "../membrane_rtc_engine/file", override: true}, - {:membrane_ice_plugin, "~> 0.18.0", override: true}, + {:membrane_rtc_engine_file, + github: "jellyfish-dev/membrane_rtc_engine", sparse: "file", override: true}, + {:membrane_ice_plugin, "~> 0.18.0"}, {:membrane_telemetry_metrics, "~> 0.1.0"}, - {:opentelemetry, "~> 1.3"}, # HLS endpoints deps {:membrane_audio_mix_plugin, "~> 0.16.0"}, diff --git a/mix.lock b/mix.lock index f0670ca8..700cba70 100644 --- a/mix.lock +++ b/mix.lock @@ -36,7 +36,7 @@ "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, "libcluster": {:hex, :libcluster, "3.3.3", "a4f17721a19004cfc4467268e17cff8b1f951befe428975dd4f6f7b84d927fe0", [:mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "7c0a2275a0bb83c07acd17dab3c3bfb4897b145106750eeccc62d302e3bdfee5"}, - "membrane_aac_fdk_plugin": {:hex, :membrane_aac_fdk_plugin, "0.18.1", "6a05536d65ed57120ce2b452e1c6077128ff1d0133909d7bc4102e43798690ae", [:mix], [{:bunch, "~> 1.4", [hex: :bunch, repo: "hexpm", optional: false]}, {:bundlex, "~> 1.3", [hex: :bundlex, repo: "hexpm", optional: false]}, {:membrane_aac_format, "~> 0.8.0", [hex: :membrane_aac_format, repo: "hexpm", optional: false]}, {:membrane_common_c, "~> 0.16.0", [hex: :membrane_common_c, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_raw_audio_format, "~> 0.12.0", [hex: :membrane_raw_audio_format, repo: "hexpm", optional: false]}, {:unifex, "~> 1.1", [hex: :unifex, repo: "hexpm", optional: false]}], "hexpm", "21d1664cd99df3529dd863d9688d718504d450f05b1037f2cbb0f08881dd9942"}, + "membrane_aac_fdk_plugin": {:hex, :membrane_aac_fdk_plugin, "0.18.5", "74a0fd9b121a9f18e038573931fa2952b95a977a4e982a844734129e977e0fb9", [:mix], [{:bunch, "~> 1.4", [hex: :bunch, repo: "hexpm", optional: false]}, {:bundlex, "~> 1.3", [hex: :bundlex, repo: "hexpm", optional: false]}, {:membrane_aac_format, "~> 0.8.0", [hex: :membrane_aac_format, repo: "hexpm", optional: false]}, {:membrane_common_c, "~> 0.16.0", [hex: :membrane_common_c, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_precompiled_dependency_provider, "~> 0.1.0", [hex: :membrane_precompiled_dependency_provider, repo: "hexpm", optional: false]}, {:membrane_raw_audio_format, "~> 0.12.0", [hex: :membrane_raw_audio_format, repo: "hexpm", optional: false]}, {:unifex, "~> 1.1", [hex: :unifex, repo: "hexpm", optional: false]}], "hexpm", "560ea01c1fc707770bcdfb30d47be5f77be3e4d86a872bc1e34261a134bf6f98"}, "membrane_aac_format": {:hex, :membrane_aac_format, "0.8.0", "515631eabd6e584e0e9af2cea80471fee6246484dbbefc4726c1d93ece8e0838", [:mix], [{:bimap, "~> 1.1", [hex: :bimap, repo: "hexpm", optional: false]}], "hexpm", "a30176a94491033ed32be45e51d509fc70a5ee6e751f12fd6c0d60bd637013f6"}, "membrane_aac_plugin": {:hex, :membrane_aac_plugin, "0.18.1", "30433bffd4d5d773f79448dd9afd55d77338721688f09a89b20d742a68cc2c3d", [:mix], [{:bunch, "~> 1.0", [hex: :bunch, repo: "hexpm", optional: false]}, {:membrane_aac_format, "~> 0.8.0", [hex: :membrane_aac_format, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}], "hexpm", "8fd048c47d5d2949eb557e19f43f62d534d3af5096187f1a1a3a1694d14b772c"}, "membrane_audio_mix_plugin": {:hex, :membrane_audio_mix_plugin, "0.16.0", "34997707ee186683c6d7bd87572944e5e37c0249235cc44915d181d653c5c40e", [:mix], [{:bunch, "~> 1.3", [hex: :bunch, repo: "hexpm", optional: false]}, {:membrane_common_c, "~> 0.16.0", [hex: :membrane_common_c, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_raw_audio_format, "~> 0.12.0", [hex: :membrane_raw_audio_format, repo: "hexpm", optional: false]}, {:unifex, "~> 1.0", [hex: :unifex, repo: "hexpm", optional: false]}], "hexpm", "a4a8c723f0da8d9cf9ac11bf657a732770ea0b8db4eff2efc16caa3a1819f435"}, @@ -46,27 +46,27 @@ "membrane_file_plugin": {:hex, :membrane_file_plugin, "0.16.0", "7917f6682c22b9bcfc2ca20ed960eee0f7d03ad31fd5f59ed850f1fe3ddd545a", [:mix], [{:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}], "hexpm", "b0727998f75a9b4dab8a2baefdfc13c3eac00a04e061ab1b0e61dc5566927acc"}, "membrane_framerate_converter_plugin": {:hex, :membrane_framerate_converter_plugin, "0.8.0", "a6f89dc89bc41e23c70f6af96e447c0577d54c0f0457a8383b652650088cb864", [:mix], [{:bunch, "~> 1.3", [hex: :bunch, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_raw_video_format, "~> 0.3.0", [hex: :membrane_raw_video_format, repo: "hexpm", optional: false]}, {:ratio, "~> 3.0", [hex: :ratio, repo: "hexpm", optional: false]}], "hexpm", "15faf8267f4d0ea3f511085bec14b90e93b6140ea4047f419e5cfbdef1543c3c"}, "membrane_funnel_plugin": {:hex, :membrane_funnel_plugin, "0.9.0", "9cfe09e44d65751f7d9d8d3c42e14797f7be69e793ac112ea63cd224af70a7bf", [:mix], [{:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}], "hexpm", "988790aca59d453a6115109f050699f7f45a2eb6a7f8dc5c96392760cddead54"}, - "membrane_h264_ffmpeg_plugin": {:hex, :membrane_h264_ffmpeg_plugin, "0.31.3", "f2117d3df369546d8c81107a47fc235b264a72d52a7a221ce06ba16d811648fa", [:mix], [{:bunch, "~> 1.6", [hex: :bunch, repo: "hexpm", optional: false]}, {:bundlex, "~> 1.3", [hex: :bundlex, repo: "hexpm", optional: false]}, {:membrane_common_c, "~> 0.16.0", [hex: :membrane_common_c, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_h264_format, "~> 0.6.1", [hex: :membrane_h264_format, repo: "hexpm", optional: false]}, {:membrane_raw_video_format, "~> 0.3.0", [hex: :membrane_raw_video_format, repo: "hexpm", optional: false]}, {:ratio, "~> 3.0", [hex: :ratio, repo: "hexpm", optional: false]}, {:unifex, "~> 1.1.0", [hex: :unifex, repo: "hexpm", optional: false]}], "hexpm", "ed8bf714e1320ad6d4b77e2f2892d8722915d0ca3973ee3e1b6aca5ee6ebaa94"}, + "membrane_h264_ffmpeg_plugin": {:hex, :membrane_h264_ffmpeg_plugin, "0.31.4", "a037365fb23ad4dea73c9176a90f777fb2f8537516530a583a1e2617da7f1b71", [:mix], [{:bunch, "~> 1.6", [hex: :bunch, repo: "hexpm", optional: false]}, {:bundlex, "~> 1.3", [hex: :bundlex, repo: "hexpm", optional: false]}, {:membrane_common_c, "~> 0.16.0", [hex: :membrane_common_c, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_h264_format, "~> 0.6.1", [hex: :membrane_h264_format, repo: "hexpm", optional: false]}, {:membrane_precompiled_dependency_provider, "~> 0.1.0", [hex: :membrane_precompiled_dependency_provider, repo: "hexpm", optional: false]}, {:membrane_raw_video_format, "~> 0.3.0", [hex: :membrane_raw_video_format, repo: "hexpm", optional: false]}, {:ratio, "~> 3.0", [hex: :ratio, repo: "hexpm", optional: false]}, {:unifex, "~> 1.1", [hex: :unifex, repo: "hexpm", optional: false]}], "hexpm", "168275f146fbd3ef0490f012921a6b6e14b820cf06990d250c0909d4efc2e46d"}, "membrane_h264_format": {:hex, :membrane_h264_format, "0.6.1", "44836cd9de0abe989b146df1e114507787efc0cf0da2368f17a10c47b4e0738c", [:mix], [], "hexpm", "4b79be56465a876d2eac2c3af99e115374bbdc03eb1dea4f696ee9a8033cd4b0"}, "membrane_h264_plugin": {:hex, :membrane_h264_plugin, "0.9.1", "ea140ab1ca21c528563675fdd7e14c80607e120e320dc930cac3dcfb4db3fc2b", [:mix], [{:bunch, "~> 1.4", [hex: :bunch, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_h264_format, "~> 0.6.0", [hex: :membrane_h264_format, repo: "hexpm", optional: false]}], "hexpm", "8f10db817e691fc1234ed85fe674b3f8718d3a410e4582736dcdd53664cae725"}, "membrane_h265_format": {:hex, :membrane_h265_format, "0.2.0", "1903c072cf7b0980c4d0c117ab61a2cd33e88782b696290de29570a7fab34819", [:mix], [], "hexpm", "6df418bdf242c0d9f7dbf2e5aea4c2d182e34ac9ad5a8b8cef2610c290002e83"}, - "membrane_http_adaptive_stream_plugin": {:hex, :membrane_http_adaptive_stream_plugin, "0.18.0", "c83dd7e921dfd595b10e12d85bde313612ece8ca64d6ff27815156b900592d16", [:mix], [{:bunch, "~> 1.6", [hex: :bunch, repo: "hexpm", optional: false]}, {:membrane_aac_plugin, "~> 0.18.0", [hex: :membrane_aac_plugin, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_h264_plugin, "~> 0.9.0", [hex: :membrane_h264_plugin, repo: "hexpm", optional: false]}, {:membrane_mp4_plugin, "~> 0.31.0", [hex: :membrane_mp4_plugin, repo: "hexpm", optional: false]}, {:membrane_tee_plugin, "~> 0.12.0", [hex: :membrane_tee_plugin, repo: "hexpm", optional: false]}, {:qex, "~> 0.5", [hex: :qex, repo: "hexpm", optional: false]}], "hexpm", "4e3a1ec9e84892d6f0b115183f4e4f3e202fcefe07aa722f7c2b107cd4403669"}, + "membrane_http_adaptive_stream_plugin": {:hex, :membrane_http_adaptive_stream_plugin, "0.18.2", "420519e956540d00bfe97594bcda893f0616c4251297500c855290fccc5f899a", [:mix], [{:bunch, "~> 1.6", [hex: :bunch, repo: "hexpm", optional: false]}, {:membrane_aac_plugin, "~> 0.18.0", [hex: :membrane_aac_plugin, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_h264_plugin, "~> 0.9.0", [hex: :membrane_h264_plugin, repo: "hexpm", optional: false]}, {:membrane_mp4_plugin, "~> 0.31.0", [hex: :membrane_mp4_plugin, repo: "hexpm", optional: false]}, {:membrane_tee_plugin, "~> 0.12.0", [hex: :membrane_tee_plugin, repo: "hexpm", optional: false]}, {:qex, "~> 0.5", [hex: :qex, repo: "hexpm", optional: false]}], "hexpm", "540cf54a85410aa2f4dd40c420a4a7da7493c0c14c5d935e84857c02ff1096fb"}, "membrane_ice_plugin": {:hex, :membrane_ice_plugin, "0.18.0", "beecb741b641b0c8b4efea0569fa68a3564051294e3ed10a10a1e29028e1d474", [:mix], [{:bunch, "~> 1.5", [hex: :bunch, repo: "hexpm", optional: false]}, {:ex_dtls, "~> 0.12.0", [hex: :ex_dtls, repo: "hexpm", optional: false]}, {:fake_turn, "~> 0.4.0", [hex: :fake_turn, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_funnel_plugin, "~> 0.9.0", [hex: :membrane_funnel_plugin, repo: "hexpm", optional: false]}, {:membrane_rtp_format, "~> 0.8.0", [hex: :membrane_rtp_format, repo: "hexpm", optional: false]}, {:membrane_telemetry_metrics, "~> 0.1.0", [hex: :membrane_telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "fff74d447d42902bb014bc8cdc78d6da3f797b59ed8fd622bfc7c6854323a287"}, "membrane_mp4_format": {:hex, :membrane_mp4_format, "0.8.0", "8c6e7d68829228117d333b4fbb030e7be829aab49dd8cb047fdc664db1812e6a", [:mix], [], "hexpm", "148dea678a1f82ccfd44dbde6f936d2f21255f496cb45a22cc6eec427f025522"}, "membrane_mp4_plugin": {:hex, :membrane_mp4_plugin, "0.31.0", "1932c86e2f4a24aca1b99ee531a131fd0da1128db8975ba8f8738e3b1bbcfabd", [:mix], [{:bunch, "~> 1.5", [hex: :bunch, repo: "hexpm", optional: false]}, {:membrane_aac_format, "~> 0.8.0", [hex: :membrane_aac_format, repo: "hexpm", optional: false]}, {:membrane_cmaf_format, "~> 0.7.0", [hex: :membrane_cmaf_format, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_file_plugin, "~> 0.16.0", [hex: :membrane_file_plugin, repo: "hexpm", optional: false]}, {:membrane_h264_format, "~> 0.6.1", [hex: :membrane_h264_format, repo: "hexpm", optional: false]}, {:membrane_h264_plugin, "~> 0.9.0", [hex: :membrane_h264_plugin, repo: "hexpm", optional: false]}, {:membrane_h265_format, "~> 0.2.0", [hex: :membrane_h265_format, repo: "hexpm", optional: false]}, {:membrane_mp4_format, "~> 0.8.0", [hex: :membrane_mp4_format, repo: "hexpm", optional: false]}, {:membrane_opus_format, "~> 0.3.0", [hex: :membrane_opus_format, repo: "hexpm", optional: false]}], "hexpm", "9968e56e02085228974bf6a59c8858f3c0d9800a4e767c1b3b2f2890050c72f4"}, "membrane_ogg_plugin": {:hex, :membrane_ogg_plugin, "0.3.0", "6e98b8932a2b88174dc3922989a475e02ee327589222b1c8422ff4fa630325c3", [:mix], [{:crc, "~> 0.10", [hex: :crc, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_opus_format, "~> 0.3.0", [hex: :membrane_opus_format, repo: "hexpm", optional: false]}], "hexpm", "82557299b3d72aab0fafa07a05dcc3a5a842eeaa3de3f2f3959677517b66b713"}, "membrane_opentelemetry": {:hex, :membrane_opentelemetry, "0.1.0", "af774bc5b9bad3a822e9a26d8530819b0291b569a282c65a7dd51cc498e6e9cd", [:mix], [{:opentelemetry_api, "~> 1.0.0", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}], "hexpm", "2e4072a5f14eb95514701e242a7667a7178dfc6afd313d4643ec0726391c243b"}, "membrane_opus_format": {:hex, :membrane_opus_format, "0.3.0", "3804d9916058b7cfa2baa0131a644d8186198d64f52d592ae09e0942513cb4c2", [:mix], [], "hexpm", "8fc89c97be50de23ded15f2050fe603dcce732566fe6fdd15a2de01cb6b81afe"}, - "membrane_opus_plugin": {:hex, :membrane_opus_plugin, "0.19.1", "1e98f01226eed8d1483b606728c399baeac9cf3d19ac101e5f095666932f1994", [:mix], [{:bunch, "~> 1.3", [hex: :bunch, repo: "hexpm", optional: false]}, {:bundlex, "~> 1.2", [hex: :bundlex, repo: "hexpm", optional: false]}, {:membrane_common_c, "~> 0.16.0", [hex: :membrane_common_c, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_opus_format, "~> 0.3.0", [hex: :membrane_opus_format, repo: "hexpm", optional: false]}, {:membrane_precompiled_dependency_provider, "~> 0.1.0", [hex: :membrane_precompiled_dependency_provider, repo: "hexpm", optional: false]}, {:membrane_raw_audio_format, "~> 0.12.0", [hex: :membrane_raw_audio_format, repo: "hexpm", optional: false]}, {:unifex, "~> 1.0", [hex: :unifex, repo: "hexpm", optional: false]}], "hexpm", "55e4c17a2d9bb8c196b549c3cbb075121beac591ce56d36f76d80a08ecf79d7d"}, + "membrane_opus_plugin": {:hex, :membrane_opus_plugin, "0.19.3", "af398a10c84d27e49b9a68ec78a54f123f2637441dd380857a3da4bb492eca5c", [:mix], [{:bunch, "~> 1.3", [hex: :bunch, repo: "hexpm", optional: false]}, {:bundlex, "~> 1.2", [hex: :bundlex, repo: "hexpm", optional: false]}, {:membrane_common_c, "~> 0.16.0", [hex: :membrane_common_c, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_opus_format, "~> 0.3.0", [hex: :membrane_opus_format, repo: "hexpm", optional: false]}, {:membrane_precompiled_dependency_provider, "~> 0.1.0", [hex: :membrane_precompiled_dependency_provider, repo: "hexpm", optional: false]}, {:membrane_raw_audio_format, "~> 0.12.0", [hex: :membrane_raw_audio_format, repo: "hexpm", optional: false]}, {:unifex, "~> 1.0", [hex: :unifex, repo: "hexpm", optional: false]}], "hexpm", "172d5637233e4e7cb2c464be34ea85b487188887381ef5ff98d5c110fdf44f5b"}, "membrane_precompiled_dependency_provider": {:hex, :membrane_precompiled_dependency_provider, "0.1.1", "a0d5b7942f8be452c30744207f78284f6a0e0c84c968aba7d76e206fbf75bc5d", [:mix], [{:bundlex, "~> 1.4", [hex: :bundlex, repo: "hexpm", optional: false]}], "hexpm", "87ad44752e2cf0fa3b31c5aac15b863343c2f6e0f0fd201f5ec4c0bcda8c6fa3"}, "membrane_raw_audio_format": {:hex, :membrane_raw_audio_format, "0.12.0", "b574cd90f69ce2a8b6201b0ccf0826ca28b0fbc8245b8078d9f11cef65f7d5d5", [:mix], [{:bimap, "~> 1.1", [hex: :bimap, repo: "hexpm", optional: false]}, {:bunch, "~> 1.0", [hex: :bunch, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}], "hexpm", "6e6c98e3622a2b9df19eab50ba65d7eb45949b1ba306fa8423df6cdb12fd0b44"}, "membrane_raw_video_format": {:hex, :membrane_raw_video_format, "0.3.0", "ba10f475e0814a6fe79602a74536b796047577c7ef5b0e33def27cd344229699", [:mix], [], "hexpm", "2f08760061c8a5386ecf04273480f10e48d25a1a40aa99476302b0bcd34ccb1c"}, "membrane_realtimer_plugin": {:hex, :membrane_realtimer_plugin, "0.9.0", "27210d5e32a5e8bfd101c41e4d8c1876e873a52cc129ebfbee4d0ccbea1cbd21", [:mix], [{:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}], "hexpm", "b2e96d62135ee57ef9a5fdea94b3a9ab1198e5ea8ee248391b89c671125d1b51"}, - "membrane_rtc_engine": {:hex, :membrane_rtc_engine, "0.19.0", "6ca3f1e1e8cd9129ac45790bec619c4b11f4abb1968dbe7f9d2884c9f3f66072", [:mix], [{:elixir_uuid, "~> 1.2", [hex: :elixir_uuid, repo: "hexpm", optional: false]}, {:ex_sdp, "~> 0.13.1", [hex: :ex_sdp, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_opentelemetry, "~> 0.1.0", [hex: :membrane_opentelemetry, repo: "hexpm", optional: false]}, {:membrane_rtp_format, "~> 0.8.0", [hex: :membrane_rtp_format, repo: "hexpm", optional: false]}, {:membrane_rtp_plugin, "~> 0.24.1", [hex: :membrane_rtp_plugin, repo: "hexpm", optional: false]}, {:opentelemetry, "~> 1.0.0", [hex: :opentelemetry, repo: "hexpm", optional: false]}, {:opentelemetry_api, "~> 1.0.0", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}, {:statistics, "~> 0.6.0", [hex: :statistics, repo: "hexpm", optional: false]}], "hexpm", "daa9da426aa1e6468bab65a0ce1c0c06187c5ec90138c8fd125f23ea2e692d85"}, - "membrane_rtc_engine_file": {:hex, :membrane_rtc_engine_file, "0.2.0", "c330a965df4ea4fa8185526b50f2b2ed4825a80780d64ae2cfb61f3af3ee7bca", [:mix], [{:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_file_plugin, "~> 0.16.0", [hex: :membrane_file_plugin, repo: "hexpm", optional: false]}, {:membrane_h264_plugin, "~> 0.9.0", [hex: :membrane_h264_plugin, repo: "hexpm", optional: false]}, {:membrane_ogg_plugin, "~> 0.3.0", [hex: :membrane_ogg_plugin, repo: "hexpm", optional: false]}, {:membrane_opus_plugin, "~> 0.19.0", [hex: :membrane_opus_plugin, repo: "hexpm", optional: false]}, {:membrane_realtimer_plugin, "~> 0.9.0", [hex: :membrane_realtimer_plugin, repo: "hexpm", optional: false]}, {:membrane_rtc_engine, "~> 0.19.0", [hex: :membrane_rtc_engine, repo: "hexpm", optional: false]}, {:membrane_rtc_engine_webrtc, "~> 0.5.0", [hex: :membrane_rtc_engine_webrtc, repo: "hexpm", optional: false]}], "hexpm", "82263a434af6c181e7045b8c7b74946947b6c29fe738f6a37398093b19fc7344"}, - "membrane_rtc_engine_hls": {:hex, :membrane_rtc_engine_hls, "0.4.0", "7a73fb67a5d3000ab5fdacf4b2d48a604f6ee57de7aaf823d3a756d0f2a4bce3", [:mix], [{:membrane_aac_fdk_plugin, "~> 0.18.1", [hex: :membrane_aac_fdk_plugin, repo: "hexpm", optional: false]}, {:membrane_aac_plugin, "~> 0.18.0", [hex: :membrane_aac_plugin, repo: "hexpm", optional: false]}, {:membrane_audio_mix_plugin, "~> 0.16.0", [hex: :membrane_audio_mix_plugin, repo: "hexpm", optional: true]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_h264_ffmpeg_plugin, "~> 0.31.0", [hex: :membrane_h264_ffmpeg_plugin, repo: "hexpm", optional: false]}, {:membrane_h264_plugin, "~> 0.9.0", [hex: :membrane_h264_plugin, repo: "hexpm", optional: false]}, {:membrane_http_adaptive_stream_plugin, "~> 0.18.0", [hex: :membrane_http_adaptive_stream_plugin, repo: "hexpm", optional: false]}, {:membrane_opus_plugin, "~> 0.19.0", [hex: :membrane_opus_plugin, repo: "hexpm", optional: false]}, {:membrane_raw_audio_format, "~> 0.12.0", [hex: :membrane_raw_audio_format, repo: "hexpm", optional: false]}, {:membrane_raw_video_format, "~> 0.3.0", [hex: :membrane_raw_video_format, repo: "hexpm", optional: false]}, {:membrane_rtc_engine, "~> 0.19.0", [hex: :membrane_rtc_engine, repo: "hexpm", optional: false]}, {:membrane_rtc_engine_webrtc, "~> 0.5.0", [hex: :membrane_rtc_engine_webrtc, repo: "hexpm", optional: false]}, {:membrane_video_compositor_plugin, "~> 0.7.0", [hex: :membrane_video_compositor_plugin, repo: "hexpm", optional: true]}], "hexpm", "e4cf04b42c255e627f59ce73482deda0bb56a81ddfd32fbc50d0a215ccf42a0a"}, + "membrane_rtc_engine": {:git, "https://github.com/jellyfish-dev/membrane_rtc_engine.git", "300841eb8eefa2885368fde433c641c5eb9c4146", [branch: "RTC-435-track-metadata", sparse: "engine"]}, + "membrane_rtc_engine_file": {:git, "https://github.com/jellyfish-dev/membrane_rtc_engine.git", "765a7a7403de672ed3f389690ef6c3974160d3ba", [sparse: "file"]}, + "membrane_rtc_engine_hls": {:git, "https://github.com/jellyfish-dev/membrane_rtc_engine.git", "765a7a7403de672ed3f389690ef6c3974160d3ba", [sparse: "hls"]}, "membrane_rtc_engine_rtsp": {:hex, :membrane_rtc_engine_rtsp, "0.4.0", "a4ed1d3aca0b8795c745d2e787e60caaa820f985fdf7ee74b144fdef4e273d4a", [:mix], [{:connection, "~> 1.1", [hex: :connection, repo: "hexpm", optional: false]}, {:ex_sdp, "~> 0.13.1", [hex: :ex_sdp, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_h264_plugin, "~> 0.9.0", [hex: :membrane_h264_plugin, repo: "hexpm", optional: false]}, {:membrane_rtc_engine, "~> 0.19.0", [hex: :membrane_rtc_engine, repo: "hexpm", optional: false]}, {:membrane_rtc_engine_webrtc, "~> 0.5.0", [hex: :membrane_rtc_engine_webrtc, repo: "hexpm", optional: false]}, {:membrane_rtp_format, "~> 0.8.0", [hex: :membrane_rtp_format, repo: "hexpm", optional: false]}, {:membrane_rtp_h264_plugin, "~> 0.19.0", [hex: :membrane_rtp_h264_plugin, repo: "hexpm", optional: false]}, {:membrane_rtp_plugin, "~> 0.24.1", [hex: :membrane_rtp_plugin, repo: "hexpm", optional: false]}, {:membrane_rtsp, "~> 0.5.1", [hex: :membrane_rtsp, repo: "hexpm", optional: false]}, {:membrane_udp_plugin, "~> 0.12.0", [hex: :membrane_udp_plugin, repo: "hexpm", optional: false]}], "hexpm", "5a74afeeeae126a704a6ae1299f7cdab79f72573ab229c66a7a1050c4e3aaf56"}, - "membrane_rtc_engine_webrtc": {:hex, :membrane_rtc_engine_webrtc, "0.5.0", "10a939c9d666daaa115ddc1112e0b4cc3380326b9aebd81ac3476273d6f12810", [:mix], [{:ex_sdp, "~> 0.13.1", [hex: :ex_sdp, repo: "hexpm", optional: false]}, {:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_file_plugin, "~> 0.16.0", [hex: :membrane_file_plugin, repo: "hexpm", optional: false]}, {:membrane_ice_plugin, "~> 0.17.0", [hex: :membrane_ice_plugin, repo: "hexpm", optional: false]}, {:membrane_opentelemetry, "~> 0.1.0", [hex: :membrane_opentelemetry, repo: "hexpm", optional: false]}, {:membrane_rtc_engine, "~> 0.19.0", [hex: :membrane_rtc_engine, repo: "hexpm", optional: false]}, {:membrane_rtp_format, "~> 0.8.0", [hex: :membrane_rtp_format, repo: "hexpm", optional: false]}, {:membrane_rtp_h264_plugin, "~> 0.19.0", [hex: :membrane_rtp_h264_plugin, repo: "hexpm", optional: false]}, {:membrane_rtp_plugin, "~> 0.24.1", [hex: :membrane_rtp_plugin, repo: "hexpm", optional: false]}, {:membrane_rtp_vp8_plugin, "~> 0.9.0", [hex: :membrane_rtp_vp8_plugin, repo: "hexpm", optional: false]}, {:membrane_telemetry_metrics, "~> 0.1.0", [hex: :membrane_telemetry_metrics, repo: "hexpm", optional: false]}, {:membrane_webrtc_plugin, "~> 0.17.0", [hex: :membrane_webrtc_plugin, repo: "hexpm", optional: false]}, {:opentelemetry_api, "~> 1.0.0", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}, {:qex, "~> 0.5", [hex: :qex, repo: "hexpm", optional: false]}], "hexpm", "11d59b4a45f90a418f72856cb2cd09b618c18b4519b6a561cdba830547da62ad"}, + "membrane_rtc_engine_webrtc": {:git, "https://github.com/jellyfish-dev/membrane_rtc_engine.git", "765a7a7403de672ed3f389690ef6c3974160d3ba", [sparse: "webrtc"]}, "membrane_rtp_format": {:hex, :membrane_rtp_format, "0.8.0", "828924bbd27efcf85b2015ae781e824c4a9928f0a7dc132abc66817b2c6edfc4", [:mix], [{:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}], "hexpm", "bc75d2a649dfaef6df563212fbb9f9f62eebc871393692f9dae8d289bd4f94bb"}, "membrane_rtp_h264_plugin": {:hex, :membrane_rtp_h264_plugin, "0.19.0", "112bfedc14fb83bdb549ef1a03da23908feedeb165fd3e4512a549f1af532ae7", [:mix], [{:bunch, "~> 1.5", [hex: :bunch, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_h264_format, "~> 0.6.0", [hex: :membrane_h264_format, repo: "hexpm", optional: false]}, {:membrane_rtp_format, "~> 0.8.0", [hex: :membrane_rtp_format, repo: "hexpm", optional: false]}], "hexpm", "76fd159e7406cadbef15124cba30eca3fffcf71a7420964f26e23d4cffd9b29d"}, "membrane_rtp_opus_plugin": {:hex, :membrane_rtp_opus_plugin, "0.9.0", "ae76421faa04697a4af76a55b6c5e675dea61b611d29d8201098783d42863af7", [:mix], [{:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_opus_format, "~> 0.3.0", [hex: :membrane_opus_format, repo: "hexpm", optional: false]}, {:membrane_rtp_format, "~> 0.8.0", [hex: :membrane_rtp_format, repo: "hexpm", optional: false]}], "hexpm", "58f095d2978daf999d87c1c016007cb7d99434208486331ab5045e77f5be9dcc"}, @@ -78,7 +78,7 @@ "membrane_udp_plugin": {:hex, :membrane_udp_plugin, "0.12.0", "f3930a592f975f5aef924ff70b1072e55451de16ec5dce7dd264ecf9d034b9ad", [:mix], [{:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:mockery, "~> 2.3.0", [hex: :mockery, repo: "hexpm", optional: false]}], "hexpm", "65e846f7523e443215b6954136971d4f00a8e8f375ef015153daa535ce607769"}, "membrane_video_compositor_plugin": {:hex, :membrane_video_compositor_plugin, "0.7.0", "2273743fd0a47660880276e0bbb8a9f8848e09b05b425101d1cc0c5d245ff8ea", [:mix], [{:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_framerate_converter_plugin, "~> 0.8.0", [hex: :membrane_framerate_converter_plugin, repo: "hexpm", optional: false]}, {:membrane_raw_video_format, "~> 0.3.0", [hex: :membrane_raw_video_format, repo: "hexpm", optional: false]}, {:qex, "~> 0.5.1", [hex: :qex, repo: "hexpm", optional: false]}, {:ratio, "~> 3.0", [hex: :ratio, repo: "hexpm", optional: false]}, {:rustler, "~> 0.26.0", [hex: :rustler, repo: "hexpm", optional: false]}, {:unifex, "~> 1.0", [hex: :unifex, repo: "hexpm", optional: false]}], "hexpm", "68ea6a5770cf053464d6fa009a20f85ca559267f5a454370506c6d40965985de"}, "membrane_vp8_format": {:hex, :membrane_vp8_format, "0.4.0", "6c29ec67479edfbab27b11266dc92f18f3baf4421262c5c31af348c33e5b92c7", [:mix], [], "hexpm", "8bb005ede61db8fcb3535a883f32168b251c2dfd1109197c8c3b39ce28ed08e2"}, - "membrane_webrtc_plugin": {:hex, :membrane_webrtc_plugin, "0.18.0", "25e279b9aa39dc12a0aa65a93bf0b702f5ace93a9cf2f9e14fc1e99e5011c0d2", [:mix], [{:bunch, "~> 1.5", [hex: :bunch, repo: "hexpm", optional: false]}, {:ex_libsrtp, ">= 0.0.0", [hex: :ex_libsrtp, repo: "hexpm", optional: false]}, {:ex_sdp, "~> 0.13.1", [hex: :ex_sdp, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_funnel_plugin, "~> 0.9.0", [hex: :membrane_funnel_plugin, repo: "hexpm", optional: false]}, {:membrane_h264_plugin, "~> 0.9.0", [hex: :membrane_h264_plugin, repo: "hexpm", optional: false]}, {:membrane_ice_plugin, "~> 0.18.0", [hex: :membrane_ice_plugin, repo: "hexpm", optional: false]}, {:membrane_rtp_format, "~> 0.8.0", [hex: :membrane_rtp_format, repo: "hexpm", optional: false]}, {:membrane_rtp_h264_plugin, "~> 0.19.0", [hex: :membrane_rtp_h264_plugin, repo: "hexpm", optional: false]}, {:membrane_rtp_opus_plugin, ">= 0.9.0", [hex: :membrane_rtp_opus_plugin, repo: "hexpm", optional: false]}, {:membrane_rtp_plugin, "~> 0.24.0", [hex: :membrane_rtp_plugin, repo: "hexpm", optional: false]}, {:membrane_rtp_vp8_plugin, "~> 0.9.0", [hex: :membrane_rtp_vp8_plugin, repo: "hexpm", optional: false]}, {:qex, "~> 0.5.0", [hex: :qex, repo: "hexpm", optional: false]}], "hexpm", "00fede6ec021611d58c23b62c3d9311ea70a38444c459e7c5a6031dea9e217f1"}, + "membrane_webrtc_plugin": {:hex, :membrane_webrtc_plugin, "0.18.1", "af5988cdfddc95174f365ce18b16694d862ab1d95bd2671297a8ab5fe65837fb", [:mix], [{:bunch, "~> 1.5", [hex: :bunch, repo: "hexpm", optional: false]}, {:ex_libsrtp, ">= 0.0.0", [hex: :ex_libsrtp, repo: "hexpm", optional: false]}, {:ex_sdp, "~> 0.13.1", [hex: :ex_sdp, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_funnel_plugin, "~> 0.9.0", [hex: :membrane_funnel_plugin, repo: "hexpm", optional: false]}, {:membrane_h264_plugin, "~> 0.9.0", [hex: :membrane_h264_plugin, repo: "hexpm", optional: false]}, {:membrane_ice_plugin, "~> 0.18.0", [hex: :membrane_ice_plugin, repo: "hexpm", optional: false]}, {:membrane_rtp_format, "~> 0.8.0", [hex: :membrane_rtp_format, repo: "hexpm", optional: false]}, {:membrane_rtp_h264_plugin, "~> 0.19.0", [hex: :membrane_rtp_h264_plugin, repo: "hexpm", optional: false]}, {:membrane_rtp_opus_plugin, ">= 0.9.0", [hex: :membrane_rtp_opus_plugin, repo: "hexpm", optional: false]}, {:membrane_rtp_plugin, "~> 0.24.0", [hex: :membrane_rtp_plugin, repo: "hexpm", optional: false]}, {:membrane_rtp_vp8_plugin, "~> 0.9.0", [hex: :membrane_rtp_vp8_plugin, repo: "hexpm", optional: false]}, {:qex, "~> 0.5.0", [hex: :qex, repo: "hexpm", optional: false]}], "hexpm", "08de22bdd3a6c9e7d79bad45b1a0eb87f335e33804a9b5afd2c84ee36428b683"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, diff --git a/openapi.yaml b/openapi.yaml index 020433d2..01a2a191 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -172,6 +172,13 @@ components: title: HlsSkip type: string x-struct: Elixir.JellyfishWeb.ApiSpec.HLS.Params.HlsSkip + PeerMetadata: + description: Custom metadata set by the peer + example: + name: JellyfishUser + nullable: true + title: PeerMetadata + x-struct: Elixir.JellyfishWeb.ApiSpec.Peer.PeerMetadata ComponentPropertiesFile: description: Properties specific to the File component properties: @@ -408,6 +415,8 @@ components: description: Assigned peer id example: peer-1 type: string + metadata: + $ref: '#/components/schemas/PeerMetadata' status: $ref: '#/components/schemas/PeerStatus' tracks: @@ -422,6 +431,7 @@ components: - type - status - tracks + - metadata title: Peer type: object x-struct: Elixir.JellyfishWeb.ApiSpec.Peer diff --git a/test/jellyfish_web/controllers/component/file_component_test.exs b/test/jellyfish_web/controllers/component/file_component_test.exs index 6d93411d..248e355e 100644 --- a/test/jellyfish_web/controllers/component/file_component_test.exs +++ b/test/jellyfish_web/controllers/component/file_component_test.exs @@ -2,11 +2,22 @@ defmodule JellyfishWeb.Component.FileComponentTest do use JellyfishWeb.ConnCase use JellyfishWeb.ComponentCase + alias JellyfishWeb.WS + + alias Jellyfish.ServerMessage.{ + Authenticated, + Track, + TrackAdded + } + @file_component_directory "file_component_sources" @fixtures_directory "test/fixtures" @video_source "video.h264" @audio_source "audio.ogg" + @ws_url "ws://127.0.0.1:4002/socket/server/websocket" + @auth_response %Authenticated{} + setup_all _tags do media_sources_directory = Application.fetch_env!(:jellyfish, :media_files_path) @@ -24,6 +35,8 @@ defmodule JellyfishWeb.Component.FileComponentTest do describe "Create File Component" do test "renders component with video as source", %{conn: conn, room_id: room_id} do + start_notifier() + conn = post(conn, ~p"/room/#{room_id}/component", type: "file", @@ -42,9 +55,23 @@ defmodule JellyfishWeb.Component.FileComponentTest do model_response(conn, :created, "ComponentDetailsResponse") assert_component_created(conn, room_id, id, "file") + + assert_receive %TrackAdded{ + room_id: ^room_id, + endpoint_info: {:component_id, ^id}, + track: %Track{} = track + } + + assert %{ + type: :TRACK_TYPE_VIDEO, + encoding: :ENCODING_H264, + metadata: "null" + } = track end test "renders component with audio as source", %{conn: conn, room_id: room_id} do + start_notifier() + conn = post(conn, ~p"/room/#{room_id}/component", type: "file", @@ -63,6 +90,18 @@ defmodule JellyfishWeb.Component.FileComponentTest do model_response(conn, :created, "ComponentDetailsResponse") assert_component_created(conn, room_id, id, "file") + + assert_receive %TrackAdded{ + room_id: ^room_id, + endpoint_info: {:component_id, ^id}, + track: %Track{} = track + } + + assert %{ + type: :TRACK_TYPE_AUDIO, + encoding: :ENCODING_OPUS, + metadata: "null" + } = track end test "file in subdirectory", %{ @@ -162,4 +201,15 @@ defmodule JellyfishWeb.Component.FileComponentTest do "Unsupported file type" end end + + defp start_notifier() do + token = Application.fetch_env!(:jellyfish, :server_api_token) + + {:ok, ws} = WS.start_link(@ws_url, :server) + WS.send_auth_request(ws, token) + assert_receive @auth_response, 1000 + WS.subscribe(ws, :server_notification) + + ws + end end diff --git a/test/jellyfish_web/integration/peer_socket_test.exs b/test/jellyfish_web/integration/peer_socket_test.exs index 25fdeae6..2ec5d83a 100644 --- a/test/jellyfish_web/integration/peer_socket_test.exs +++ b/test/jellyfish_web/integration/peer_socket_test.exs @@ -3,7 +3,7 @@ defmodule JellyfishWeb.Integration.PeerSocketTest do alias __MODULE__.Endpoint alias Jellyfish.PeerMessage - alias Jellyfish.PeerMessage.{Authenticated, AuthRequest, MediaEvent} + alias Jellyfish.PeerMessage.{Authenticated, MediaEvent} alias Jellyfish.RoomService alias JellyfishWeb.{PeerSocket, WS} @@ -62,8 +62,7 @@ defmodule JellyfishWeb.Integration.PeerSocketTest do test "invalid token", %{token: token} do {:ok, ws} = WS.start_link(@path, :peer) - auth_request = auth_request("invalid" <> token) - :ok = WS.send_binary_frame(ws, auth_request) + WS.send_auth_request(ws, "invalid" <> token) assert_receive {:disconnected, {:remote, 1000, "invalid token"}}, 1000 end @@ -76,9 +75,7 @@ defmodule JellyfishWeb.Integration.PeerSocketTest do {:ok, ws} = WS.start_link(@path, :peer) unadded_peer_token = JellyfishWeb.PeerToken.generate(%{peer_id: "peer_id", room_id: room_id}) - auth_request = auth_request(unadded_peer_token) - - :ok = WS.send_binary_frame(ws, auth_request) + WS.send_auth_request(ws, unadded_peer_token) assert_receive {:disconnected, {:remote, 1000, "peer not found"}}, 1000 end @@ -87,8 +84,7 @@ defmodule JellyfishWeb.Integration.PeerSocketTest do _conn = delete(conn, ~p"/room/#{room_id}") {:ok, ws} = WS.start_link(@path, :peer) - auth_request = auth_request(token) - :ok = WS.send_binary_frame(ws, auth_request) + WS.send_auth_request(ws, token) assert_receive {:disconnected, {:remote, 1000, "room not found"}}, 1000 end @@ -96,8 +92,7 @@ defmodule JellyfishWeb.Integration.PeerSocketTest do test "authRequest when already connected", %{token: token} do ws = create_and_authenticate(token) - auth_request = auth_request(token) - :ok = WS.send_binary_frame(ws, auth_request) + WS.send_auth_request(ws, token) refute_receive @auth_response, 1000 refute_receive {:disconnected, {:remote, 1000, _msg}} end @@ -106,8 +101,7 @@ defmodule JellyfishWeb.Integration.PeerSocketTest do create_and_authenticate(token) {:ok, ws2} = WS.start_link(@path, :peer) - auth_request = auth_request(token) - :ok = WS.send_binary_frame(ws2, auth_request) + WS.send_auth_request(ws2, token) assert_receive {:disconnected, {:remote, 1000, "peer already connected"}}, 1000 end @@ -169,16 +163,10 @@ defmodule JellyfishWeb.Integration.PeerSocketTest do end def create_and_authenticate(token) do - auth_request = auth_request(token) - {:ok, ws} = WS.start_link(@path, :peer) - :ok = WS.send_binary_frame(ws, auth_request) + WS.send_auth_request(ws, token) assert_receive @auth_response, 1000 ws end - - defp auth_request(token) do - PeerMessage.encode(%PeerMessage{content: {:auth_request, %AuthRequest{token: token}}}) - end end diff --git a/test/jellyfish_web/integration/server_notification_test.exs b/test/jellyfish_web/integration/server_notification_test.exs index a1c60422..d13c42a1 100644 --- a/test/jellyfish_web/integration/server_notification_test.exs +++ b/test/jellyfish_web/integration/server_notification_test.exs @@ -3,6 +3,8 @@ defmodule JellyfishWeb.Integration.ServerNotificationTest do import Mox + import JellyfishWeb.WS, only: [subscribe: 2] + alias __MODULE__.Endpoint alias Jellyfish.Component.HLS @@ -13,7 +15,6 @@ defmodule JellyfishWeb.Integration.ServerNotificationTest do alias Jellyfish.ServerMessage.{ Authenticated, - AuthRequest, HlsPlayable, HlsUploadCrashed, HlsUploaded, @@ -24,8 +25,6 @@ defmodule JellyfishWeb.Integration.ServerNotificationTest do RoomCrashed, RoomCreated, RoomDeleted, - SubscribeRequest, - SubscribeResponse, Track, TrackAdded, TrackRemoved @@ -115,9 +114,8 @@ defmodule JellyfishWeb.Integration.ServerNotificationTest do test "invalid token" do {:ok, ws} = WS.start_link(@path, :server) server_api_token = "invalid" <> Application.fetch_env!(:jellyfish, :server_api_token) - auth_request = auth_request(server_api_token) + WS.send_auth_request(ws, server_api_token) - :ok = WS.send_binary_frame(ws, auth_request) assert_receive {:disconnected, {:remote, 1000, "invalid token"}}, 1000 end @@ -368,8 +366,7 @@ defmodule JellyfishWeb.Integration.ServerNotificationTest do {room_id, peer_id, peer_token, _conn} = add_room_and_peer(conn, server_api_token) {:ok, peer_ws} = WS.start_link("ws://127.0.0.1:#{@port}/socket/peer/websocket", :peer) - auth_request = peer_auth_request(peer_token) - :ok = WS.send_binary_frame(peer_ws, auth_request) + WS.send_auth_request(peer_ws, peer_token) assert_receive %PeerConnected{peer_id: ^peer_id, room_id: ^room_id} @@ -393,8 +390,7 @@ defmodule JellyfishWeb.Integration.ServerNotificationTest do add_room_and_peer(conn, server_api_token) {:ok, peer_ws} = WS.start("ws://127.0.0.1:#{@port}/socket/peer/websocket", :peer) - auth_request = peer_auth_request(peer_token) - :ok = WS.send_binary_frame(peer_ws, auth_request) + WS.send_auth_request(peer_ws, peer_token) assert_receive %PeerConnected{peer_id: ^peer_id, room_id: ^room_id} @@ -406,32 +402,14 @@ defmodule JellyfishWeb.Integration.ServerNotificationTest do def create_and_authenticate() do token = Application.fetch_env!(:jellyfish, :server_api_token) - auth_request = auth_request(token) {:ok, ws} = WS.start_link(@path, :server) - :ok = WS.send_binary_frame(ws, auth_request) + WS.send_auth_request(ws, token) assert_receive @auth_response, 1000 ws end - def subscribe(ws, event_type) do - proto_event_type = to_proto_event_type(event_type) - - msg = %ServerMessage{ - content: - {:subscribe_request, - %SubscribeRequest{ - event_type: proto_event_type - }} - } - - :ok = WS.send_binary_frame(ws, ServerMessage.encode(msg)) - - assert_receive %SubscribeResponse{event_type: ^proto_event_type} = response - response - end - defp add_room_and_peer(conn, server_api_token) do conn = put_req_header(conn, "authorization", "Bearer " <> server_api_token) @@ -484,28 +462,14 @@ defmodule JellyfishWeb.Integration.ServerNotificationTest do {conn, id} end - defp auth_request(token) do - ServerMessage.encode(%ServerMessage{content: {:auth_request, %AuthRequest{token: token}}}) - end - - defp peer_auth_request(token) do - PeerMessage.encode(%PeerMessage{ - content: {:auth_request, %PeerMessage.AuthRequest{token: token}} - }) - end - defp trigger_notification(conn) do server_api_token = Application.fetch_env!(:jellyfish, :server_api_token) {_room_id, _peer_id, peer_token, _conn} = add_room_and_peer(conn, server_api_token) {:ok, peer_ws} = WS.start_link("ws://127.0.0.1:#{@port}/socket/peer/websocket", :peer) - auth_request = peer_auth_request(peer_token) - :ok = WS.send_binary_frame(peer_ws, auth_request) + WS.send_auth_request(peer_ws, peer_token) end - defp to_proto_event_type(:server_notification), do: :EVENT_TYPE_SERVER_NOTIFICATION - defp to_proto_event_type(:metrics), do: :EVENT_TYPE_METRICS - defp test_hls_manager(room_id, request_no: request_no, status_code: status_code) do hls_dir = HLS.output_dir(room_id, persistent: false) options = %{s3: @s3_credentials, persistent: false} diff --git a/test/support/ws.ex b/test/support/ws.ex index 09787e9e..cd004922 100644 --- a/test/support/ws.ex +++ b/test/support/ws.ex @@ -6,16 +6,41 @@ defmodule JellyfishWeb.WS do alias Jellyfish.PeerMessage alias Jellyfish.ServerMessage + @spec start(String.t(), :server | :peer) :: {:ok, pid()} | {:error, term()} def start(url, type) do state = %{caller: self(), type: type} WebSockex.start(url, __MODULE__, state) end + @spec start_link(String.t(), :server | :peer) :: {:ok, pid()} | {:error, term()} def start_link(url, type) do state = %{caller: self(), type: type} WebSockex.start_link(url, __MODULE__, state) end + def send_auth_request(ws, token) do + send(ws, {:authenticate, token}) + end + + def subscribe(ws, event_type) do + proto_event_type = to_proto_event_type(event_type) + + msg = %ServerMessage{ + content: + {:subscribe_request, + %ServerMessage.SubscribeRequest{ + event_type: proto_event_type + }} + } + + :ok = send_binary_frame(ws, ServerMessage.encode(msg)) + + import ExUnit.Assertions + + assert_receive %ServerMessage.SubscribeResponse{event_type: ^proto_event_type} = response + response + end + def send_frame(ws, msg) do WebSockex.send_frame(ws, {:text, Jason.encode!(msg)}) end @@ -41,6 +66,12 @@ defmodule JellyfishWeb.WS do {:ok, state} end + @impl true + def handle_info({:authenticate, token}, state) do + request = auth_request(state.type, token) + {:reply, {:binary, request}, state} + end + @impl true def handle_disconnect(conn_status, state) do send(state.caller, {:disconnected, conn_status.reason}) @@ -56,4 +87,19 @@ defmodule JellyfishWeb.WS do %ServerMessage{content: {_atom, content}} = ServerMessage.decode(msg) content end + + defp auth_request(:peer, token) do + PeerMessage.encode(%PeerMessage{ + content: {:auth_request, %PeerMessage.AuthRequest{token: token}} + }) + end + + defp auth_request(:server, token) do + ServerMessage.encode(%ServerMessage{ + content: {:auth_request, %ServerMessage.AuthRequest{token: token}} + }) + end + + defp to_proto_event_type(:server_notification), do: :EVENT_TYPE_SERVER_NOTIFICATION + defp to_proto_event_type(:metrics), do: :EVENT_TYPE_METRICS end From 122192cd1767ca67a39e4faab5b2f385ec301e49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Wed, 31 Jan 2024 13:47:01 +0100 Subject: [PATCH 08/21] Improve handling Engine messages --- lib/jellyfish/event.ex | 3 +- lib/jellyfish/room.ex | 78 +++++++++---------- .../component/file_component_test.exs | 21 ++++- 3 files changed, 60 insertions(+), 42 deletions(-) diff --git a/lib/jellyfish/event.ex b/lib/jellyfish/event.ex index bd3c4f8d..efc1d382 100644 --- a/lib/jellyfish/event.ex +++ b/lib/jellyfish/event.ex @@ -116,8 +116,7 @@ defmodule Jellyfish.Event do } end - defp to_proto_track(%type{} = track) - when type in [Message.TrackAdded, Message.TrackMetadataUpdated, Message.TrackRemoved] do + defp to_proto_track(%Message.TrackAdded{} = track) do %Track{ id: track.track_id, type: to_proto_track_type(track.track_type), diff --git a/lib/jellyfish/room.ex b/lib/jellyfish/room.ex index 19a8d4d2..e13e6fa9 100644 --- a/lib/jellyfish/room.ex +++ b/lib/jellyfish/room.ex @@ -481,7 +481,11 @@ defmodule Jellyfish.Room do {:track_added, state.id, {endpoint_id_type, endpoint_id}, track_info} ) - state = add_track(state, track_info) + endpoint_group = get_endpoint_group(state, track_info.endpoint_id) + access_path = [endpoint_group, track_info.endpoint_id, :tracks, track_info.track_id] + + track = Track.from_track_added_message(track_info) + state = put_in(state, access_path, track) {:noreply, state} end @@ -498,43 +502,54 @@ defmodule Jellyfish.Room do endpoint_group = get_endpoint_group(state, endpoint_id) access_path = [endpoint_group, endpoint_id, :tracks, track_info.track_id] - state = - case get_in(state, access_path) do - nil -> - Logger.warning( - "Unable to update track's metadata - track #{inspect(track_info.track_id)} doesn't exist" - ) + case get_in(state, access_path) do + nil -> + Logger.warning( + "Unable to update track's metadata - track #{inspect(track_info.track_id)} doesn't exist" + ) - state + {:noreply, state} - track -> - endpoint_id_type = get_endpoint_id_type(state, endpoint_id) + track -> + endpoint_id_type = get_endpoint_id_type(state, endpoint_id) + updated_track = %Track{track | metadata: track_info.track_metadata} - Event.broadcast_server_notification( - {:track_metadata_updated, state.id, {endpoint_id_type, endpoint_id}, track_info} - ) + Logger.debug( + "Track #{updated_track.id}, #{endpoint_id_type}: #{endpoint_id} - metadata updated: #{updated_track.metadata}" + ) - track = %Track{track | metadata: track_info.track_metadata} - put_in(state, access_path, track) - end + Event.broadcast_server_notification( + {:track_metadata_updated, state.id, {endpoint_id_type, endpoint_id}, updated_track} + ) - {:noreply, state} + {:noreply, put_in(state, access_path, updated_track)} + end end @impl true def handle_info(%TrackRemoved{endpoint_id: endpoint_id} = track_info, state) when endpoint_exists?(state, endpoint_id) do - Logger.info("Endpoint #{endpoint_id} removed track #{inspect(track_info)}") + endpoint_group = get_endpoint_group(state, endpoint_id) + access_path = [endpoint_group, endpoint_id, :tracks, track_info.track_id] - endpoint_id_type = get_endpoint_id_type(state, endpoint_id) + case get_in(state, access_path) do + nil -> + Logger.warning( + "Unable to remove track - track #{inspect(track_info.track_id)} doesn't exist" + ) - Event.broadcast_server_notification( - {:track_added, state.id, {endpoint_id_type, endpoint_id}, track_info} - ) + {:noreply, state} - state = remove_track(state, track_info) + track -> + endpoint_id_type = get_endpoint_id_type(state, endpoint_id) + Logger.debug("Track removed: #{track.id}, #{endpoint_id_type}: #{endpoint_id}") - {:noreply, state} + Event.broadcast_server_notification( + {:track_removed, state.id, {endpoint_id_type, endpoint_id}, track} + ) + + {:noreply, pop_in(state, access_path)} + end end @impl true @@ -677,21 +692,6 @@ defmodule Jellyfish.Room do defp get_endpoint_group(state, endpoint_id) when is_map_key(state.peers, endpoint_id), do: :peers - defp add_track(state, track_info) do - track = Track.from_track_added_message(track_info) - put_in(state, get_track_keys(state, track_info), track) - end - - defp remove_track(state, track_info) do - {_track, state} = pop_in(state, get_track_keys(state, track_info)) - state - end - - defp get_track_keys(state, track_info) do - endpoint_group = get_endpoint_group(state, track_info.endpoint_id) - [endpoint_group, track_info.endpoint_id, :tracks, track_info.track_id] - end - defp get_endpoint_id_type(state, endpoint_id) do case get_endpoint_group(state, endpoint_id) do :peers -> :peer_id diff --git a/test/jellyfish_web/controllers/component/file_component_test.exs b/test/jellyfish_web/controllers/component/file_component_test.exs index 248e355e..f55b54c6 100644 --- a/test/jellyfish_web/controllers/component/file_component_test.exs +++ b/test/jellyfish_web/controllers/component/file_component_test.exs @@ -7,7 +7,8 @@ defmodule JellyfishWeb.Component.FileComponentTest do alias Jellyfish.ServerMessage.{ Authenticated, Track, - TrackAdded + TrackAdded, + TrackRemoved } @file_component_directory "file_component_sources" @@ -67,6 +68,15 @@ defmodule JellyfishWeb.Component.FileComponentTest do encoding: :ENCODING_H264, metadata: "null" } = track + + conn = delete(conn, ~p"/room/#{room_id}/component/#{id}") + assert response(conn, :no_content) + + assert_receive %TrackRemoved{ + room_id: ^room_id, + endpoint_info: {:component_id, ^id}, + track: ^track + } end test "renders component with audio as source", %{conn: conn, room_id: room_id} do @@ -102,6 +112,15 @@ defmodule JellyfishWeb.Component.FileComponentTest do encoding: :ENCODING_OPUS, metadata: "null" } = track + + conn = delete(conn, ~p"/room/#{room_id}/component/#{id}") + assert response(conn, :no_content) + + assert_receive %TrackRemoved{ + room_id: ^room_id, + endpoint_info: {:component_id, ^id}, + track: ^track + } end test "file in subdirectory", %{ From 74081f5672fb27e13ae307608a192674647211dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Wed, 31 Jan 2024 15:45:04 +0100 Subject: [PATCH 09/21] Improve logging --- lib/jellyfish/room.ex | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/jellyfish/room.ex b/lib/jellyfish/room.ex index e13e6fa9..30821e92 100644 --- a/lib/jellyfish/room.ex +++ b/lib/jellyfish/room.ex @@ -458,7 +458,7 @@ defmodule Jellyfish.Room do state ) when is_map_key(state.peers, endpoint_id) do - Logger.debug("Peer #{endpoint_id} metadata updated: #{metadata}") + Logger.info("Peer #{endpoint_id} metadata updated: #{metadata}") Event.broadcast_server_notification({:peer_metadata_updated, state.id, endpoint_id, metadata}) state = put_in(state, [:peers, endpoint_id, :metadata], metadata) @@ -473,10 +473,10 @@ defmodule Jellyfish.Room do @impl true def handle_info(%TrackAdded{endpoint_id: endpoint_id} = track_info, state) when endpoint_exists?(state, endpoint_id) do - Logger.info("Endpoint #{endpoint_id} added track #{inspect(track_info)}") - endpoint_id_type = get_endpoint_id_type(state, endpoint_id) + Logger.info("Track #{track_info.track_id} added, #{endpoint_id_type}: #{endpoint_id}") + Event.broadcast_server_notification( {:track_added, state.id, {endpoint_id_type, endpoint_id}, track_info} ) @@ -514,7 +514,7 @@ defmodule Jellyfish.Room do endpoint_id_type = get_endpoint_id_type(state, endpoint_id) updated_track = %Track{track | metadata: track_info.track_metadata} - Logger.debug( + Logger.info( "Track #{updated_track.id}, #{endpoint_id_type}: #{endpoint_id} - metadata updated: #{updated_track.metadata}" ) @@ -526,6 +526,12 @@ defmodule Jellyfish.Room do end end + @impl true + def handle_info(%TrackMetadataUpdated{endpoint_id: endpoint_id} = track_info, state) do + Logger.error("Unknown endpoint #{endpoint_id} updated track #{inspect(track_info)}") + {:noreply, state} + end + @impl true def handle_info(%TrackRemoved{endpoint_id: endpoint_id} = track_info, state) when endpoint_exists?(state, endpoint_id) do @@ -542,7 +548,7 @@ defmodule Jellyfish.Room do track -> endpoint_id_type = get_endpoint_id_type(state, endpoint_id) - Logger.debug("Track removed: #{track.id}, #{endpoint_id_type}: #{endpoint_id}") + Logger.info("Track removed: #{track.id}, #{endpoint_id_type}: #{endpoint_id}") Event.broadcast_server_notification( {:track_removed, state.id, {endpoint_id_type, endpoint_id}, track} @@ -558,11 +564,6 @@ defmodule Jellyfish.Room do {:noreply, state} end - @impl true - def handle_info(%EndpointRemoved{}, state) do - {:noreply, state} - end - @impl true def handle_info(info, state) do Logger.warning("Received unexpected info: #{inspect(info)}") From b5ce44f85bc438b0220e86df359dfeaedc189f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Wed, 31 Jan 2024 15:54:59 +0100 Subject: [PATCH 10/21] Remove unused deps --- mix.lock | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mix.lock b/mix.lock index 700cba70..dbc229a8 100644 --- a/mix.lock +++ b/mix.lock @@ -55,7 +55,6 @@ "membrane_mp4_format": {:hex, :membrane_mp4_format, "0.8.0", "8c6e7d68829228117d333b4fbb030e7be829aab49dd8cb047fdc664db1812e6a", [:mix], [], "hexpm", "148dea678a1f82ccfd44dbde6f936d2f21255f496cb45a22cc6eec427f025522"}, "membrane_mp4_plugin": {:hex, :membrane_mp4_plugin, "0.31.0", "1932c86e2f4a24aca1b99ee531a131fd0da1128db8975ba8f8738e3b1bbcfabd", [:mix], [{:bunch, "~> 1.5", [hex: :bunch, repo: "hexpm", optional: false]}, {:membrane_aac_format, "~> 0.8.0", [hex: :membrane_aac_format, repo: "hexpm", optional: false]}, {:membrane_cmaf_format, "~> 0.7.0", [hex: :membrane_cmaf_format, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_file_plugin, "~> 0.16.0", [hex: :membrane_file_plugin, repo: "hexpm", optional: false]}, {:membrane_h264_format, "~> 0.6.1", [hex: :membrane_h264_format, repo: "hexpm", optional: false]}, {:membrane_h264_plugin, "~> 0.9.0", [hex: :membrane_h264_plugin, repo: "hexpm", optional: false]}, {:membrane_h265_format, "~> 0.2.0", [hex: :membrane_h265_format, repo: "hexpm", optional: false]}, {:membrane_mp4_format, "~> 0.8.0", [hex: :membrane_mp4_format, repo: "hexpm", optional: false]}, {:membrane_opus_format, "~> 0.3.0", [hex: :membrane_opus_format, repo: "hexpm", optional: false]}], "hexpm", "9968e56e02085228974bf6a59c8858f3c0d9800a4e767c1b3b2f2890050c72f4"}, "membrane_ogg_plugin": {:hex, :membrane_ogg_plugin, "0.3.0", "6e98b8932a2b88174dc3922989a475e02ee327589222b1c8422ff4fa630325c3", [:mix], [{:crc, "~> 0.10", [hex: :crc, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_opus_format, "~> 0.3.0", [hex: :membrane_opus_format, repo: "hexpm", optional: false]}], "hexpm", "82557299b3d72aab0fafa07a05dcc3a5a842eeaa3de3f2f3959677517b66b713"}, - "membrane_opentelemetry": {:hex, :membrane_opentelemetry, "0.1.0", "af774bc5b9bad3a822e9a26d8530819b0291b569a282c65a7dd51cc498e6e9cd", [:mix], [{:opentelemetry_api, "~> 1.0.0", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}], "hexpm", "2e4072a5f14eb95514701e242a7667a7178dfc6afd313d4643ec0726391c243b"}, "membrane_opus_format": {:hex, :membrane_opus_format, "0.3.0", "3804d9916058b7cfa2baa0131a644d8186198d64f52d592ae09e0942513cb4c2", [:mix], [], "hexpm", "8fc89c97be50de23ded15f2050fe603dcce732566fe6fdd15a2de01cb6b81afe"}, "membrane_opus_plugin": {:hex, :membrane_opus_plugin, "0.19.3", "af398a10c84d27e49b9a68ec78a54f123f2637441dd380857a3da4bb492eca5c", [:mix], [{:bunch, "~> 1.3", [hex: :bunch, repo: "hexpm", optional: false]}, {:bundlex, "~> 1.2", [hex: :bundlex, repo: "hexpm", optional: false]}, {:membrane_common_c, "~> 0.16.0", [hex: :membrane_common_c, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_opus_format, "~> 0.3.0", [hex: :membrane_opus_format, repo: "hexpm", optional: false]}, {:membrane_precompiled_dependency_provider, "~> 0.1.0", [hex: :membrane_precompiled_dependency_provider, repo: "hexpm", optional: false]}, {:membrane_raw_audio_format, "~> 0.12.0", [hex: :membrane_raw_audio_format, repo: "hexpm", optional: false]}, {:unifex, "~> 1.0", [hex: :unifex, repo: "hexpm", optional: false]}], "hexpm", "172d5637233e4e7cb2c464be34ea85b487188887381ef5ff98d5c110fdf44f5b"}, "membrane_precompiled_dependency_provider": {:hex, :membrane_precompiled_dependency_provider, "0.1.1", "a0d5b7942f8be452c30744207f78284f6a0e0c84c968aba7d76e206fbf75bc5d", [:mix], [{:bundlex, "~> 1.4", [hex: :bundlex, repo: "hexpm", optional: false]}], "hexpm", "87ad44752e2cf0fa3b31c5aac15b863343c2f6e0f0fd201f5ec4c0bcda8c6fa3"}, @@ -89,9 +88,6 @@ "nimble_pool": {:hex, :nimble_pool, "1.0.0", "5eb82705d138f4dd4423f69ceb19ac667b3b492ae570c9f5c900bb3d2f50a847", [:mix], [], "hexpm", "80be3b882d2d351882256087078e1b1952a28bf98d0a287be87e4a24a710b67a"}, "numbers": {:hex, :numbers, "5.2.4", "f123d5bb7f6acc366f8f445e10a32bd403c8469bdbce8ce049e1f0972b607080", [:mix], [{:coerce, "~> 1.0", [hex: :coerce, repo: "hexpm", optional: false]}, {:decimal, "~> 1.9 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "eeccf5c61d5f4922198395bf87a465b6f980b8b862dd22d28198c5e6fab38582"}, "open_api_spex": {:hex, :open_api_spex, "3.18.0", "f9952b6bc8a1bf14168f3754981b7c8d72d015112bfedf2588471dd602e1e715", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:ymlr, "~> 2.0 or ~> 3.0 or ~> 4.0", [hex: :ymlr, repo: "hexpm", optional: true]}], "hexpm", "37849887ab67efab052376401fac28c0974b273ffaecd98f4532455ca0886464"}, - "opentelemetry": {:hex, :opentelemetry, "1.3.1", "f0a342a74379e3540a634e7047967733da4bc8b873ec9026e224b2bd7369b1fc", [:rebar3], [{:opentelemetry_api, "~> 1.2.2", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}, {:opentelemetry_semantic_conventions, "~> 0.2", [hex: :opentelemetry_semantic_conventions, repo: "hexpm", optional: false]}], "hexpm", "de476b2ac4faad3e3fe3d6e18b35dec9cb338c3b9910c2ce9317836dacad3483"}, - "opentelemetry_api": {:hex, :opentelemetry_api, "1.2.2", "693f47b0d8c76da2095fe858204cfd6350c27fe85d00e4b763deecc9588cf27a", [:mix, :rebar3], [{:opentelemetry_semantic_conventions, "~> 0.2", [hex: :opentelemetry_semantic_conventions, repo: "hexpm", optional: false]}], "hexpm", "dc77b9a00f137a858e60a852f14007bb66eda1ffbeb6c05d5fe6c9e678b05e9d"}, - "opentelemetry_semantic_conventions": {:hex, :opentelemetry_semantic_conventions, "0.2.0", "b67fe459c2938fcab341cb0951c44860c62347c005ace1b50f8402576f241435", [:mix, :rebar3], [], "hexpm", "d61fa1f5639ee8668d74b527e6806e0503efc55a42db7b5f39939d84c07d6895"}, "p1_utils": {:hex, :p1_utils, "1.0.23", "7f94466ada69bd982ea7bb80fbca18e7053e7d0b82c9d9e37621fa508587069b", [:rebar3], [], "hexpm", "47f21618694eeee5006af1c88731ad86b757161e7823c29b6f73921b571c8502"}, "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"}, "patiently": {:hex, :patiently, "0.2.0", "67eb139591e10c4b363ae0198e832552f191c58894731efd3bf124ec4722267a", [:mix], [], "hexpm", "c08cc5edc27def565647a9b55a0bea8025a5f81a4472e57692f28f2292c44c94"}, From 41c17a0eca16deccd369417d7c0a1088d1ba7836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Wed, 31 Jan 2024 16:17:04 +0100 Subject: [PATCH 11/21] RTC-engine dependency to master --- mix.exs | 5 +---- mix.lock | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/mix.exs b/mix.exs index 29040dd2..825ee345 100644 --- a/mix.exs +++ b/mix.exs @@ -69,10 +69,7 @@ defmodule Jellyfish.MixProject do # Membrane deps {:membrane_rtc_engine, - github: "jellyfish-dev/membrane_rtc_engine", - branch: "RTC-435-track-metadata", - sparse: "engine", - override: true}, + github: "jellyfish-dev/membrane_rtc_engine", sparse: "engine", override: true}, {:membrane_rtc_engine_webrtc, github: "jellyfish-dev/membrane_rtc_engine", sparse: "webrtc", override: true}, {:membrane_rtc_engine_hls, diff --git a/mix.lock b/mix.lock index dbc229a8..ac250bd5 100644 --- a/mix.lock +++ b/mix.lock @@ -61,7 +61,7 @@ "membrane_raw_audio_format": {:hex, :membrane_raw_audio_format, "0.12.0", "b574cd90f69ce2a8b6201b0ccf0826ca28b0fbc8245b8078d9f11cef65f7d5d5", [:mix], [{:bimap, "~> 1.1", [hex: :bimap, repo: "hexpm", optional: false]}, {:bunch, "~> 1.0", [hex: :bunch, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}], "hexpm", "6e6c98e3622a2b9df19eab50ba65d7eb45949b1ba306fa8423df6cdb12fd0b44"}, "membrane_raw_video_format": {:hex, :membrane_raw_video_format, "0.3.0", "ba10f475e0814a6fe79602a74536b796047577c7ef5b0e33def27cd344229699", [:mix], [], "hexpm", "2f08760061c8a5386ecf04273480f10e48d25a1a40aa99476302b0bcd34ccb1c"}, "membrane_realtimer_plugin": {:hex, :membrane_realtimer_plugin, "0.9.0", "27210d5e32a5e8bfd101c41e4d8c1876e873a52cc129ebfbee4d0ccbea1cbd21", [:mix], [{:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}], "hexpm", "b2e96d62135ee57ef9a5fdea94b3a9ab1198e5ea8ee248391b89c671125d1b51"}, - "membrane_rtc_engine": {:git, "https://github.com/jellyfish-dev/membrane_rtc_engine.git", "300841eb8eefa2885368fde433c641c5eb9c4146", [branch: "RTC-435-track-metadata", sparse: "engine"]}, + "membrane_rtc_engine": {:git, "https://github.com/jellyfish-dev/membrane_rtc_engine.git", "164b5dc3fa2f56a5da696e5173794f37acce7959", [sparse: "engine"]}, "membrane_rtc_engine_file": {:git, "https://github.com/jellyfish-dev/membrane_rtc_engine.git", "765a7a7403de672ed3f389690ef6c3974160d3ba", [sparse: "file"]}, "membrane_rtc_engine_hls": {:git, "https://github.com/jellyfish-dev/membrane_rtc_engine.git", "765a7a7403de672ed3f389690ef6c3974160d3ba", [sparse: "hls"]}, "membrane_rtc_engine_rtsp": {:hex, :membrane_rtc_engine_rtsp, "0.4.0", "a4ed1d3aca0b8795c745d2e787e60caaa820f985fdf7ee74b144fdef4e273d4a", [:mix], [{:connection, "~> 1.1", [hex: :connection, repo: "hexpm", optional: false]}, {:ex_sdp, "~> 0.13.1", [hex: :ex_sdp, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_h264_plugin, "~> 0.9.0", [hex: :membrane_h264_plugin, repo: "hexpm", optional: false]}, {:membrane_rtc_engine, "~> 0.19.0", [hex: :membrane_rtc_engine, repo: "hexpm", optional: false]}, {:membrane_rtc_engine_webrtc, "~> 0.5.0", [hex: :membrane_rtc_engine_webrtc, repo: "hexpm", optional: false]}, {:membrane_rtp_format, "~> 0.8.0", [hex: :membrane_rtp_format, repo: "hexpm", optional: false]}, {:membrane_rtp_h264_plugin, "~> 0.19.0", [hex: :membrane_rtp_h264_plugin, repo: "hexpm", optional: false]}, {:membrane_rtp_plugin, "~> 0.24.1", [hex: :membrane_rtp_plugin, repo: "hexpm", optional: false]}, {:membrane_rtsp, "~> 0.5.1", [hex: :membrane_rtsp, repo: "hexpm", optional: false]}, {:membrane_udp_plugin, "~> 0.12.0", [hex: :membrane_udp_plugin, repo: "hexpm", optional: false]}], "hexpm", "5a74afeeeae126a704a6ae1299f7cdab79f72573ab229c66a7a1050c4e3aaf56"}, From e74f0d32e8a4e33a8af063e85d2b4c4d6ea6bfd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Fri, 2 Feb 2024 14:26:21 +0100 Subject: [PATCH 12/21] Improve handling unexpected messages --- lib/jellyfish/room.ex | 24 ++++++++++--------- lib/jellyfish/track.ex | 7 +++--- lib/jellyfish/webhook_notifier.ex | 2 +- .../component/file_component_test.exs | 8 +------ 4 files changed, 19 insertions(+), 22 deletions(-) diff --git a/lib/jellyfish/room.ex b/lib/jellyfish/room.ex index 30821e92..919664c7 100644 --- a/lib/jellyfish/room.ex +++ b/lib/jellyfish/room.ex @@ -484,7 +484,7 @@ defmodule Jellyfish.Room do endpoint_group = get_endpoint_group(state, track_info.endpoint_id) access_path = [endpoint_group, track_info.endpoint_id, :tracks, track_info.track_id] - track = Track.from_track_added_message(track_info) + track = Track.from_track_message(track_info) state = put_in(state, access_path, track) {:noreply, state} @@ -502,13 +502,13 @@ defmodule Jellyfish.Room do endpoint_group = get_endpoint_group(state, endpoint_id) access_path = [endpoint_group, endpoint_id, :tracks, track_info.track_id] - case get_in(state, access_path) do + update_in(state, access_path, fn nil -> Logger.warning( - "Unable to update track's metadata - track #{inspect(track_info.track_id)} doesn't exist" + "Metadata updated of an unknown track #{inspect(track_info)}, new track added" ) - {:noreply, state} + Track.from_track_message(track_info) track -> endpoint_id_type = get_endpoint_id_type(state, endpoint_id) @@ -522,8 +522,9 @@ defmodule Jellyfish.Room do {:track_metadata_updated, state.id, {endpoint_id_type, endpoint_id}, updated_track} ) - {:noreply, put_in(state, access_path, updated_track)} - end + updated_track + end) + |> then(&{:noreply, &1}) end @impl true @@ -538,15 +539,15 @@ defmodule Jellyfish.Room do endpoint_group = get_endpoint_group(state, endpoint_id) access_path = [endpoint_group, endpoint_id, :tracks, track_info.track_id] - case get_in(state, access_path) do - nil -> + case pop_in(state, access_path) do + {nil, state} -> Logger.warning( "Unable to remove track - track #{inspect(track_info.track_id)} doesn't exist" ) - {:noreply, state} + state - track -> + {track, state} -> endpoint_id_type = get_endpoint_id_type(state, endpoint_id) Logger.info("Track removed: #{track.id}, #{endpoint_id_type}: #{endpoint_id}") @@ -554,8 +555,9 @@ defmodule Jellyfish.Room do {:track_removed, state.id, {endpoint_id_type, endpoint_id}, track} ) - {:noreply, pop_in(state, access_path)} + state end + |> then(&{:noreply, &1}) end @impl true diff --git a/lib/jellyfish/track.ex b/lib/jellyfish/track.ex index cee1dd1c..ee956ed4 100644 --- a/lib/jellyfish/track.ex +++ b/lib/jellyfish/track.ex @@ -5,7 +5,7 @@ defmodule Jellyfish.Track do use Bunch.Access - alias Membrane.RTC.Engine.Message.TrackAdded + alias Membrane.RTC.Engine.Message.{TrackAdded, TrackMetadataUpdated} @enforce_keys [:id, :type, :encoding] defstruct @enforce_keys ++ [:metadata] @@ -19,8 +19,9 @@ defmodule Jellyfish.Track do metadata: nil | any() } - @spec from_track_added_message(TrackAdded.t()) :: t() - def from_track_added_message(message) do + @spec from_track_message(TrackAdded.t() | TrackMetadataUpdated.t()) :: t() + def from_track_message(%type{} = message) + when type in [TrackAdded, TrackMetadataUpdated] do %__MODULE__{ id: message.track_id, type: message.track_type, diff --git a/lib/jellyfish/webhook_notifier.ex b/lib/jellyfish/webhook_notifier.ex index c2d083be..4fd50a43 100644 --- a/lib/jellyfish/webhook_notifier.ex +++ b/lib/jellyfish/webhook_notifier.ex @@ -51,7 +51,7 @@ defmodule Jellyfish.WebhookNotifier do case HTTPoison.post( webhook_url, notification, - [{"Content-Type", "application/octet-stream"}] + [{"Content-Type", "application/protobuf"}] ) do {:ok, result} when result.status_code >= 200 and result.status_code < 300 -> nil diff --git a/test/jellyfish_web/controllers/component/file_component_test.exs b/test/jellyfish_web/controllers/component/file_component_test.exs index f55b54c6..dd2d2d42 100644 --- a/test/jellyfish_web/controllers/component/file_component_test.exs +++ b/test/jellyfish_web/controllers/component/file_component_test.exs @@ -60,15 +60,9 @@ defmodule JellyfishWeb.Component.FileComponentTest do assert_receive %TrackAdded{ room_id: ^room_id, endpoint_info: {:component_id, ^id}, - track: %Track{} = track + track: %Track{type: :TRACK_TYPE_VIDEO, encoding: :ENCODING_H264, metadata: "null"} = track } - assert %{ - type: :TRACK_TYPE_VIDEO, - encoding: :ENCODING_H264, - metadata: "null" - } = track - conn = delete(conn, ~p"/room/#{room_id}/component/#{id}") assert response(conn, :no_content) From abbddefe947c8b98714e33a12407d73f9337a982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Fri, 2 Feb 2024 14:32:15 +0100 Subject: [PATCH 13/21] Remove track encoding --- lib/jellyfish/event.ex | 7 ------- lib/jellyfish/track.ex | 4 +--- lib/jellyfish_web/api_spec/track.ex | 4 ---- lib/protos/jellyfish/server_notifications.pb.ex | 14 +------------- openapi.yaml | 6 ------ .../controllers/component/file_component_test.exs | 3 +-- .../integration/server_notification_test.exs | 5 ++--- 7 files changed, 5 insertions(+), 38 deletions(-) diff --git a/lib/jellyfish/event.ex b/lib/jellyfish/event.ex index efc1d382..f8a73f36 100644 --- a/lib/jellyfish/event.ex +++ b/lib/jellyfish/event.ex @@ -111,7 +111,6 @@ defmodule Jellyfish.Event do %Track{ id: track.id, type: to_proto_track_type(track.type), - encoding: to_proto_encoding(track.encoding), metadata: Jason.encode!(track.metadata) } end @@ -120,16 +119,10 @@ defmodule Jellyfish.Event do %Track{ id: track.track_id, type: to_proto_track_type(track.track_type), - encoding: to_proto_encoding(track.track_encoding), metadata: Jason.encode!(track.track_metadata) } end - defp to_proto_encoding(:H264), do: :ENCODING_H264 - defp to_proto_encoding(:VP8), do: :ENCODING_VP8 - defp to_proto_encoding(:OPUS), do: :ENCODING_OPUS - defp to_proto_encoding(_encoding), do: :ENCODING_UNSPECIFIED - defp to_proto_track_type(:video), do: :TRACK_TYPE_VIDEO defp to_proto_track_type(:audio), do: :TRACK_TYPE_AUDIO defp to_proto_track_type(_type), do: :TRACK_TYPE_UNSPECIFIED diff --git a/lib/jellyfish/track.ex b/lib/jellyfish/track.ex index ee956ed4..418d0382 100644 --- a/lib/jellyfish/track.ex +++ b/lib/jellyfish/track.ex @@ -7,7 +7,7 @@ defmodule Jellyfish.Track do alias Membrane.RTC.Engine.Message.{TrackAdded, TrackMetadataUpdated} - @enforce_keys [:id, :type, :encoding] + @enforce_keys [:id, :type] defstruct @enforce_keys ++ [:metadata] @type id() :: String.t() @@ -15,7 +15,6 @@ defmodule Jellyfish.Track do @type t() :: %__MODULE__{ id: id(), type: :audio | :video, - encoding: atom(), metadata: nil | any() } @@ -25,7 +24,6 @@ defmodule Jellyfish.Track do %__MODULE__{ id: message.track_id, type: message.track_type, - encoding: message.track_encoding, metadata: message.track_metadata } end diff --git a/lib/jellyfish_web/api_spec/track.ex b/lib/jellyfish_web/api_spec/track.ex index 7012407b..a12c4358 100644 --- a/lib/jellyfish_web/api_spec/track.ex +++ b/lib/jellyfish_web/api_spec/track.ex @@ -16,10 +16,6 @@ defmodule JellyfishWeb.ApiSpec.Track do type: :string, enum: ["audio", "video"] }, - encoding: %Schema{ - type: :string, - enum: ["H264", "VP8", "OPUS"] - }, metadata: %Schema{ nullable: true } diff --git a/lib/protos/jellyfish/server_notifications.pb.ex b/lib/protos/jellyfish/server_notifications.pb.ex index 62919cf6..5348b6c5 100644 --- a/lib/protos/jellyfish/server_notifications.pb.ex +++ b/lib/protos/jellyfish/server_notifications.pb.ex @@ -8,17 +8,6 @@ defmodule Jellyfish.ServerMessage.EventType do field :EVENT_TYPE_METRICS, 2 end -defmodule Jellyfish.ServerMessage.Encoding do - @moduledoc false - - use Protobuf, enum: true, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" - - field :ENCODING_UNSPECIFIED, 0 - field :ENCODING_H264, 1 - field :ENCODING_VP8, 2 - field :ENCODING_OPUS, 3 -end - defmodule Jellyfish.ServerMessage.TrackType do @moduledoc false @@ -175,8 +164,7 @@ defmodule Jellyfish.ServerMessage.Track do field :id, 1, type: :string field :type, 2, type: Jellyfish.ServerMessage.TrackType, enum: true - field :encoding, 3, type: Jellyfish.ServerMessage.Encoding, enum: true - field :metadata, 4, type: :string + field :metadata, 3, type: :string end defmodule Jellyfish.ServerMessage.TrackAdded do diff --git a/openapi.yaml b/openapi.yaml index 01a2a191..be8e0baa 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -356,12 +356,6 @@ components: Track: description: Describes media track of a Peer or Component properties: - encoding: - enum: - - H264 - - VP8 - - OPUS - type: string id: type: string metadata: diff --git a/test/jellyfish_web/controllers/component/file_component_test.exs b/test/jellyfish_web/controllers/component/file_component_test.exs index dd2d2d42..46f05bf0 100644 --- a/test/jellyfish_web/controllers/component/file_component_test.exs +++ b/test/jellyfish_web/controllers/component/file_component_test.exs @@ -60,7 +60,7 @@ defmodule JellyfishWeb.Component.FileComponentTest do assert_receive %TrackAdded{ room_id: ^room_id, endpoint_info: {:component_id, ^id}, - track: %Track{type: :TRACK_TYPE_VIDEO, encoding: :ENCODING_H264, metadata: "null"} = track + track: %Track{type: :TRACK_TYPE_VIDEO, metadata: "null"} = track } conn = delete(conn, ~p"/room/#{room_id}/component/#{id}") @@ -103,7 +103,6 @@ defmodule JellyfishWeb.Component.FileComponentTest do assert %{ type: :TRACK_TYPE_AUDIO, - encoding: :ENCODING_OPUS, metadata: "null" } = track diff --git a/test/jellyfish_web/integration/server_notification_test.exs b/test/jellyfish_web/integration/server_notification_test.exs index d13c42a1..1037afd9 100644 --- a/test/jellyfish_web/integration/server_notification_test.exs +++ b/test/jellyfish_web/integration/server_notification_test.exs @@ -289,7 +289,6 @@ defmodule JellyfishWeb.Integration.ServerNotificationTest do %Track{ id: _track_id, type: :TRACK_TYPE_VIDEO, - encoding: :ENCODING_H264, metadata: "null" } = track_info @@ -331,9 +330,9 @@ defmodule JellyfishWeb.Integration.ServerNotificationTest do room_id: ^room_id, peer_id: ^peer_id, metadata: ^metadata_encoded - } = track_added + } = peer_metadata_updated - assert_receive {:webhook_notification, ^track_added}, 1_000 + assert_receive {:webhook_notification, ^peer_metadata_updated}, 1_000 end describe "hls upload" do From 6877c493140ee1fff185b221e5a76127a4e92b93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Tue, 6 Feb 2024 11:20:57 +0100 Subject: [PATCH 14/21] Remove unused cases --- lib/jellyfish/room.ex | 56 ++++++++++++------------------- lib/jellyfish/webhook_notifier.ex | 2 +- 2 files changed, 22 insertions(+), 36 deletions(-) diff --git a/lib/jellyfish/room.ex b/lib/jellyfish/room.ex index 919664c7..d808b75c 100644 --- a/lib/jellyfish/room.ex +++ b/lib/jellyfish/room.ex @@ -502,29 +502,24 @@ defmodule Jellyfish.Room do endpoint_group = get_endpoint_group(state, endpoint_id) access_path = [endpoint_group, endpoint_id, :tracks, track_info.track_id] - update_in(state, access_path, fn - nil -> - Logger.warning( - "Metadata updated of an unknown track #{inspect(track_info)}, new track added" - ) - - Track.from_track_message(track_info) + state = + update_in(state, access_path, fn + track -> + endpoint_id_type = get_endpoint_id_type(state, endpoint_id) + updated_track = %Track{track | metadata: track_info.track_metadata} - track -> - endpoint_id_type = get_endpoint_id_type(state, endpoint_id) - updated_track = %Track{track | metadata: track_info.track_metadata} + Logger.info( + "Track #{updated_track.id}, #{endpoint_id_type}: #{endpoint_id} - metadata updated: #{updated_track.metadata}" + ) - Logger.info( - "Track #{updated_track.id}, #{endpoint_id_type}: #{endpoint_id} - metadata updated: #{updated_track.metadata}" - ) + Event.broadcast_server_notification( + {:track_metadata_updated, state.id, {endpoint_id_type, endpoint_id}, updated_track} + ) - Event.broadcast_server_notification( - {:track_metadata_updated, state.id, {endpoint_id_type, endpoint_id}, updated_track} - ) + updated_track + end) - updated_track - end) - |> then(&{:noreply, &1}) + {:noreply, state} end @impl true @@ -539,25 +534,16 @@ defmodule Jellyfish.Room do endpoint_group = get_endpoint_group(state, endpoint_id) access_path = [endpoint_group, endpoint_id, :tracks, track_info.track_id] - case pop_in(state, access_path) do - {nil, state} -> - Logger.warning( - "Unable to remove track - track #{inspect(track_info.track_id)} doesn't exist" - ) - - state + {track, state} = pop_in(state, access_path) - {track, state} -> - endpoint_id_type = get_endpoint_id_type(state, endpoint_id) - Logger.info("Track removed: #{track.id}, #{endpoint_id_type}: #{endpoint_id}") + endpoint_id_type = get_endpoint_id_type(state, endpoint_id) + Logger.info("Track removed: #{track.id}, #{endpoint_id_type}: #{endpoint_id}") - Event.broadcast_server_notification( - {:track_removed, state.id, {endpoint_id_type, endpoint_id}, track} - ) + Event.broadcast_server_notification( + {:track_removed, state.id, {endpoint_id_type, endpoint_id}, track} + ) - state - end - |> then(&{:noreply, &1}) + {:noreply, state} end @impl true diff --git a/lib/jellyfish/webhook_notifier.ex b/lib/jellyfish/webhook_notifier.ex index 4fd50a43..2ac0cdf7 100644 --- a/lib/jellyfish/webhook_notifier.ex +++ b/lib/jellyfish/webhook_notifier.ex @@ -51,7 +51,7 @@ defmodule Jellyfish.WebhookNotifier do case HTTPoison.post( webhook_url, notification, - [{"Content-Type", "application/protobuf"}] + [{"Content-Type", "application/x-protobuf"}] ) do {:ok, result} when result.status_code >= 200 and result.status_code < 300 -> nil From ba562036210cd04566b508fb69d4baa2f091965e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Tue, 6 Feb 2024 11:26:14 +0100 Subject: [PATCH 15/21] Fix logging --- lib/jellyfish/room.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/jellyfish/room.ex b/lib/jellyfish/room.ex index d808b75c..ef75bfa2 100644 --- a/lib/jellyfish/room.ex +++ b/lib/jellyfish/room.ex @@ -458,7 +458,7 @@ defmodule Jellyfish.Room do state ) when is_map_key(state.peers, endpoint_id) do - Logger.info("Peer #{endpoint_id} metadata updated: #{metadata}") + Logger.info("Peer #{endpoint_id} metadata updated: #{inspect(metadata)}") Event.broadcast_server_notification({:peer_metadata_updated, state.id, endpoint_id, metadata}) state = put_in(state, [:peers, endpoint_id, :metadata], metadata) @@ -509,7 +509,7 @@ defmodule Jellyfish.Room do updated_track = %Track{track | metadata: track_info.track_metadata} Logger.info( - "Track #{updated_track.id}, #{endpoint_id_type}: #{endpoint_id} - metadata updated: #{updated_track.metadata}" + "Track #{updated_track.id}, #{endpoint_id_type}: #{endpoint_id} - metadata updated: #{inspect(updated_track.metadata)}" ) Event.broadcast_server_notification( From 02626a4abf444d5a1abea9a1605433c8633ab5d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Tue, 6 Feb 2024 11:47:14 +0100 Subject: [PATCH 16/21] Remove unused deps --- mix.lock | 2 -- 1 file changed, 2 deletions(-) diff --git a/mix.lock b/mix.lock index 208f780f..740bf1df 100644 --- a/mix.lock +++ b/mix.lock @@ -88,8 +88,6 @@ "nimble_pool": {:hex, :nimble_pool, "1.0.0", "5eb82705d138f4dd4423f69ceb19ac667b3b492ae570c9f5c900bb3d2f50a847", [:mix], [], "hexpm", "80be3b882d2d351882256087078e1b1952a28bf98d0a287be87e4a24a710b67a"}, "numbers": {:hex, :numbers, "5.2.4", "f123d5bb7f6acc366f8f445e10a32bd403c8469bdbce8ce049e1f0972b607080", [:mix], [{:coerce, "~> 1.0", [hex: :coerce, repo: "hexpm", optional: false]}, {:decimal, "~> 1.9 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "eeccf5c61d5f4922198395bf87a465b6f980b8b862dd22d28198c5e6fab38582"}, "open_api_spex": {:hex, :open_api_spex, "3.18.2", "8c855e83bfe8bf81603d919d6e892541eafece3720f34d1700b58024dadde247", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:ymlr, "~> 2.0 or ~> 3.0 or ~> 4.0", [hex: :ymlr, repo: "hexpm", optional: true]}], "hexpm", "aa3e6dcfc0ad6a02596b2172662da21c9dd848dac145ea9e603f54e3d81b8d2b"}, - "opentelemetry": {:hex, :opentelemetry, "1.0.5", "f0cd36ac8b30b68e8d70cec5bb88801ed7f3fe79aac67597054ed5490542e810", [:rebar3], [{:opentelemetry_api, "~> 1.0", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}], "hexpm", "3b17f8933a58e1246f42a0c215840fd8218aebbcabdb0aac62b0c766fe85542e"}, - "opentelemetry_api": {:hex, :opentelemetry_api, "1.0.3", "77f9644c42340cd8b18c728cde4822ed55ae136f0d07761b78e8c54da46af93a", [:mix, :rebar3], [], "hexpm", "4293e06bd369bc004e6fad5edbb56456d891f14bd3f9f1772b18f1923e0678ea"}, "p1_utils": {:hex, :p1_utils, "1.0.23", "7f94466ada69bd982ea7bb80fbca18e7053e7d0b82c9d9e37621fa508587069b", [:rebar3], [], "hexpm", "47f21618694eeee5006af1c88731ad86b757161e7823c29b6f73921b571c8502"}, "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"}, "patiently": {:hex, :patiently, "0.2.0", "67eb139591e10c4b363ae0198e832552f191c58894731efd3bf124ec4722267a", [:mix], [], "hexpm", "c08cc5edc27def565647a9b55a0bea8025a5f81a4472e57692f28f2292c44c94"}, From 634e2137c054d018adada400f34c964b56f7c7ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Tue, 6 Feb 2024 11:56:35 +0100 Subject: [PATCH 17/21] Format --- test/jellyfish_web/controllers/component/file_component_test.exs | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jellyfish_web/controllers/component/file_component_test.exs b/test/jellyfish_web/controllers/component/file_component_test.exs index e17b556a..60b25878 100644 --- a/test/jellyfish_web/controllers/component/file_component_test.exs +++ b/test/jellyfish_web/controllers/component/file_component_test.exs @@ -100,6 +100,7 @@ defmodule JellyfishWeb.Component.FileComponentTest do test "renders component wiht audio as source", %{conn: conn, room_id: room_id} do start_notifier() + conn = post(conn, ~p"/room/#{room_id}/component", type: "file", From 76ca6c1b4df966599e2a20c9e8b61c0a1c846c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Tue, 6 Feb 2024 15:34:34 +0100 Subject: [PATCH 18/21] Fix sending track_removed notifications --- lib/jellyfish/room.ex | 81 ++++++++++++------- lib/jellyfish/room_service.ex | 2 - lib/jellyfish_web/peer_socket.ex | 10 +-- .../component/file_component_test.exs | 2 +- 4 files changed, 59 insertions(+), 36 deletions(-) diff --git a/lib/jellyfish/room.ex b/lib/jellyfish/room.ex index b512034f..bc03f6c9 100644 --- a/lib/jellyfish/room.ex +++ b/lib/jellyfish/room.ex @@ -227,16 +227,7 @@ defmodule Jellyfish.Room do def handle_call({:remove_peer, peer_id}, _from, state) do {reply, state} = if Map.has_key?(state.peers, peer_id) do - {peer, state} = pop_in(state, [:peers, peer_id]) - :ok = Engine.remove_endpoint(state.engine_pid, peer_id) - - if is_pid(peer.socket_pid), - do: send(peer.socket_pid, {:stop_connection, :peer_removed}) - - Logger.info("Removed peer #{inspect(peer_id)} from room #{inspect(state.id)}") - - if peer.status == :connected, - do: Event.broadcast_server_notification({:peer_disconnected, state.id, peer_id}) + state = handle_remove_peer(peer_id, state, :peer_removed) {:ok, state} else @@ -318,21 +309,7 @@ defmodule Jellyfish.Room do def handle_call({:remove_component, component_id}, _from, state) do {reply, state} = if Map.has_key?(state.components, component_id) do - {component, state} = pop_in(state, [:components, component_id]) - :ok = Engine.remove_endpoint(state.engine_pid, component_id) - - component.tracks - |> Map.values() - |> Enum.each( - &Event.broadcast_server_notification( - {:track_removed, state.id, {:component_id, component_id}, &1} - ) - ) - - Logger.info("Removed component #{inspect(component_id)}") - - if component.type == HLS, do: on_hls_removal(state.id, component.properties) - + state = handle_remove_component(component_id, state) {:ok, state} else {{:error, :component_not_found}, state} @@ -343,7 +320,7 @@ defmodule Jellyfish.Room do @impl true def handle_call({:hls_subscribe, origins}, _from, state) do - hls_component = hls_component(state) + hls_component = get_hls_component(state) reply = case validate_hls_subscription(hls_component) do @@ -577,9 +554,17 @@ defmodule Jellyfish.Room do def terminate(_reason, %{engine_pid: engine_pid} = state) do Engine.terminate(engine_pid, asynchronous?: true, timeout: 10_000) - hls_component = hls_component(state) + hls_component = get_hls_component(state) unless is_nil(hls_component), do: on_hls_removal(state.id, hls_component.properties) + state.peers + |> Map.values() + |> Enum.each(&handle_remove_peer(&1.id, state, :room_stopped)) + + state.components + |> Map.values() + |> Enum.each(&handle_remove_component(&1.id, state)) + :ok end @@ -621,7 +606,47 @@ defmodule Jellyfish.Room do } end - defp hls_component(%{components: components}), + defp handle_remove_component(component_id, state) do + {component, state} = pop_in(state, [:components, component_id]) + :ok = Engine.remove_endpoint(state.engine_pid, component_id) + + component.tracks + |> Map.values() + |> Enum.each( + &Event.broadcast_server_notification( + {:track_removed, state.id, {:component_id, component_id}, &1} + ) + ) + + Logger.info("Removed component #{inspect(component_id)}") + + if component.type == HLS, do: on_hls_removal(state.id, component.properties) + + state + end + + defp handle_remove_peer(peer_id, state, reason) do + {peer, state} = pop_in(state, [:peers, peer_id]) + :ok = Engine.remove_endpoint(state.engine_pid, peer_id) + + if is_pid(peer.socket_pid), + do: send(peer.socket_pid, {:stop_connection, reason}) + + peer.tracks + |> Map.values() + |> Enum.each( + &Event.broadcast_server_notification({:track_removed, state.id, {:peer_id, peer_id}, &1}) + ) + + Logger.info("Removed peer #{inspect(peer_id)} from room #{inspect(state.id)}") + + if peer.status == :connected and reason == :peer_removed, + do: Event.broadcast_server_notification({:peer_disconnected, state.id, peer_id}) + + state + end + + defp get_hls_component(%{components: components}), do: Enum.find_value(components, fn {_id, component} -> if component.type == HLS, do: component diff --git a/lib/jellyfish/room_service.ex b/lib/jellyfish/room_service.ex index 21b2352b..688ef513 100644 --- a/lib/jellyfish/room_service.ex +++ b/lib/jellyfish/room_service.ex @@ -203,8 +203,6 @@ defmodule Jellyfish.RoomService do Logger.debug("Room #{room_id} is down with reason: normal") - Phoenix.PubSub.broadcast(Jellyfish.PubSub, room_id, :room_stopped) - {:noreply, state} end diff --git a/lib/jellyfish_web/peer_socket.ex b/lib/jellyfish_web/peer_socket.ex index b7b1e62e..ec2a61f9 100644 --- a/lib/jellyfish_web/peer_socket.ex +++ b/lib/jellyfish_web/peer_socket.ex @@ -119,18 +119,18 @@ defmodule JellyfishWeb.PeerSocket do end @impl true - def handle_info({:stop_connection, _reason}, state) do - {:stop, :closed, {1011, "Internal server error"}, state} + def handle_info({:stop_connection, :room_stopped}, state) do + {:stop, :closed, {1000, "Room stopped"}, state} end @impl true - def handle_info(:room_crashed, state) do + def handle_info({:stop_connection, _reason}, state) do {:stop, :closed, {1011, "Internal server error"}, state} end @impl true - def handle_info(:room_stopped, state) do - {:stop, :closed, {1000, "Room stopped"}, state} + def handle_info(:room_crashed, state) do + {:stop, :closed, {1011, "Internal server error"}, state} end @impl true diff --git a/test/jellyfish_web/controllers/component/file_component_test.exs b/test/jellyfish_web/controllers/component/file_component_test.exs index 60b25878..56b5f915 100644 --- a/test/jellyfish_web/controllers/component/file_component_test.exs +++ b/test/jellyfish_web/controllers/component/file_component_test.exs @@ -98,7 +98,7 @@ defmodule JellyfishWeb.Component.FileComponentTest do assert_component_created(conn, room_id, id, "file") end - test "renders component wiht audio as source", %{conn: conn, room_id: room_id} do + test "renders component with audio as source", %{conn: conn, room_id: room_id} do start_notifier() conn = From 19f8318d7ff87546a53802316a4d17d515cdfb39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Wed, 7 Feb 2024 10:42:39 +0100 Subject: [PATCH 19/21] PR remarks --- lib/jellyfish/room.ex | 2 +- .../controllers/component/file_component_test.exs | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/jellyfish/room.ex b/lib/jellyfish/room.ex index bc03f6c9..a30e9f1c 100644 --- a/lib/jellyfish/room.ex +++ b/lib/jellyfish/room.ex @@ -496,7 +496,7 @@ defmodule Jellyfish.Room do state = update_in(state, access_path, fn - track -> + %Track{} = track -> endpoint_id_type = get_endpoint_id_type(state, endpoint_id) updated_track = %Track{track | metadata: track_info.track_metadata} diff --git a/test/jellyfish_web/controllers/component/file_component_test.exs b/test/jellyfish_web/controllers/component/file_component_test.exs index 56b5f915..67a4e6d8 100644 --- a/test/jellyfish_web/controllers/component/file_component_test.exs +++ b/test/jellyfish_web/controllers/component/file_component_test.exs @@ -123,14 +123,13 @@ defmodule JellyfishWeb.Component.FileComponentTest do assert_receive %TrackAdded{ room_id: ^room_id, endpoint_info: {:component_id, ^id}, - track: %Track{} = track + track: + %{ + type: :TRACK_TYPE_AUDIO, + metadata: "null" + } = track } - assert %{ - type: :TRACK_TYPE_AUDIO, - metadata: "null" - } = track - conn = delete(conn, ~p"/room/#{room_id}/component/#{id}") assert response(conn, :no_content) From 466931a73463a2ef5a2a07b60b12c47d2927f816 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Wed, 7 Feb 2024 15:54:07 +0100 Subject: [PATCH 20/21] Synchronize protos --- protos | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protos b/protos index 37818482..cb67f49c 160000 --- a/protos +++ b/protos @@ -1 +1 @@ -Subproject commit 3781848239f67a88866f861fa798a8c18384e666 +Subproject commit cb67f49c47250daf9a97f1296ef7be8965ef4acf From ff8556a7465aa1e20a703fb8780b58b2f289df6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Wed, 7 Feb 2024 16:06:45 +0100 Subject: [PATCH 21/21] Add lint ignores --- .redocly.lint-ignore.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.redocly.lint-ignore.yaml b/.redocly.lint-ignore.yaml index c58c898a..bbe2ba26 100644 --- a/.redocly.lint-ignore.yaml +++ b/.redocly.lint-ignore.yaml @@ -3,5 +3,8 @@ openapi.yaml: no-empty-servers: - '#/servers' + operation-4xx-response: + - '#/paths/~1health/get/responses' spec: - '#/components/schemas/Track/properties/metadata/nullable' + - '#/components/schemas/PeerMetadata/nullable'