From 3ee24a6c0ca3fc035f5d9331aabeb82373ca87f5 Mon Sep 17 00:00:00 2001 From: KarolK99 Date: Fri, 24 Nov 2023 15:18:40 +0100 Subject: [PATCH 1/2] add hls subscription --- lib/jellyfish/hls.ex | 27 ++++++++++++++++++ test/jellyfish/hls_test.exs | 55 +++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 lib/jellyfish/hls.ex create mode 100644 test/jellyfish/hls_test.exs diff --git a/lib/jellyfish/hls.ex b/lib/jellyfish/hls.ex new file mode 100644 index 0000000..aa22cb2 --- /dev/null +++ b/lib/jellyfish/hls.ex @@ -0,0 +1,27 @@ +defmodule Jellyfish.HLS do + @moduledoc """ + Utilities for manipulating the hls component. + """ + + alias Tesla.Env + alias Jellyfish.{Client, Room, Utils} + + @type track_id :: String.t() + + @doc """ + Adds tracks to hls component + """ + @spec subscribe(Client.t(), Room.id(), [track_id()]) :: :ok | {:error, atom() | String.t()} + def subscribe(client, room_id, tracks) do + with :ok <- validate_tracks(tracks), + {:ok, %Env{status: 201}} <- + Tesla.post(client.http_client, "/hls/#{room_id}/subscribe", %{tracks: tracks}) do + :ok + else + error -> Utils.handle_response_error(error) + end + end + + defp validate_tracks(tracks) when is_list(tracks), do: :ok + defp validate_tracks(_tracks), do: {:error, :tracks_validation} +end diff --git a/test/jellyfish/hls_test.exs b/test/jellyfish/hls_test.exs new file mode 100644 index 0000000..a763abb --- /dev/null +++ b/test/jellyfish/hls_test.exs @@ -0,0 +1,55 @@ +defmodule Jellyfish.HLSTest do + use ExUnit.Case + + alias Jellyfish.{Client, Component, HLS, Room} + + @max_peers 10 + @video_codec :h264 + + @valid_tracks ["track-id"] + @invalid_tracks %{id: "track-id"} + @wrong_room_id "wrong-id" + + setup do + client = Client.new() + + {:ok, %Jellyfish.Room{id: id}, _jellyfish_address} = + Room.create(client, max_peers: @max_peers, video_codec: @video_codec) + + %{client: client, room_id: id} + end + + describe "HLS.subscribe/3" do + test "when request is valid", %{client: client, room_id: room_id} do + assert {:ok, %Component{metadata: %{subscribe_mode: "manual"}}} = + Room.add_component(client, room_id, %Component.HLS{subscribe_mode: :manual}) + + assert :ok = HLS.subscribe(client, room_id, @valid_tracks) + end + + test "when room doesn't exist", %{client: client} do + assert {:error, "Request failed: Room #{@wrong_room_id} does not exist"} = + HLS.subscribe(client, @wrong_room_id, @valid_tracks) + end + + test "when hls component doesn't exist", %{client: client, room_id: room_id} do + assert {:error, "Request failed: HLS component does not exist"} = + HLS.subscribe(client, room_id, @valid_tracks) + end + + test "when hls component has subscribe mode :auto", %{client: client, room_id: room_id} do + assert {:ok, %Component{metadata: %{subscribe_mode: "auto"}}} = + Room.add_component(client, room_id, %Jellyfish.Component.HLS{subscribe_mode: :auto}) + + assert {:error, "Request failed: HLS component option `subscribe_mode` is set to :auto"} = + HLS.subscribe(client, room_id, @valid_tracks) + end + + test "when request is invalid", %{client: client, room_id: room_id} do + assert {:ok, %Component{metadata: %{subscribe_mode: "manual"}}} = + Room.add_component(client, room_id, %Component.HLS{subscribe_mode: :manual}) + + assert {:error, :tracks_validation} = HLS.subscribe(client, room_id, @invalid_tracks) + end + end +end From a75bab78ed1e466d2f735527ab0151fac43b5999 Mon Sep 17 00:00:00 2001 From: Karol Konkol Date: Tue, 28 Nov 2023 17:37:38 +0100 Subject: [PATCH 2/2] Refactor hls subscription --- lib/jellyfish/hls.ex | 27 ------------------ lib/jellyfish/room.ex | 22 +++++++++++++++ test/jellyfish/hls_test.exs | 55 ------------------------------------ test/jellyfish/room_test.exs | 39 +++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 82 deletions(-) delete mode 100644 lib/jellyfish/hls.ex delete mode 100644 test/jellyfish/hls_test.exs diff --git a/lib/jellyfish/hls.ex b/lib/jellyfish/hls.ex deleted file mode 100644 index aa22cb2..0000000 --- a/lib/jellyfish/hls.ex +++ /dev/null @@ -1,27 +0,0 @@ -defmodule Jellyfish.HLS do - @moduledoc """ - Utilities for manipulating the hls component. - """ - - alias Tesla.Env - alias Jellyfish.{Client, Room, Utils} - - @type track_id :: String.t() - - @doc """ - Adds tracks to hls component - """ - @spec subscribe(Client.t(), Room.id(), [track_id()]) :: :ok | {:error, atom() | String.t()} - def subscribe(client, room_id, tracks) do - with :ok <- validate_tracks(tracks), - {:ok, %Env{status: 201}} <- - Tesla.post(client.http_client, "/hls/#{room_id}/subscribe", %{tracks: tracks}) do - :ok - else - error -> Utils.handle_response_error(error) - end - end - - defp validate_tracks(tracks) when is_list(tracks), do: :ok - defp validate_tracks(_tracks), do: {:error, :tracks_validation} -end diff --git a/lib/jellyfish/room.ex b/lib/jellyfish/room.ex index e78f347..7a8d8ad 100644 --- a/lib/jellyfish/room.ex +++ b/lib/jellyfish/room.ex @@ -51,6 +51,11 @@ defmodule Jellyfish.Room do """ @type id :: String.t() + @typedoc """ + Id of the track, unique within Jellyfish instance. + """ + @type track_id :: String.t() + @typedoc """ Peer token, created by Jellyfish. Required by client application to open connection to Jellyfish. """ @@ -236,6 +241,20 @@ defmodule Jellyfish.Room do end end + @doc """ + Adds tracks to hls component + """ + @spec hls_subscribe(Client.t(), id(), [track_id()]) :: :ok | {:error, atom() | String.t()} + def hls_subscribe(client, room_id, tracks) do + with :ok <- validate_tracks(tracks), + {:ok, %Env{status: 201}} <- + Tesla.post(client.http_client, "/hls/#{room_id}/subscribe", %{tracks: tracks}) do + :ok + else + error -> Utils.handle_response_error(error) + end + end + @doc false @spec from_json(map()) :: t() def from_json(response) do @@ -285,6 +304,9 @@ defmodule Jellyfish.Room do defp validate_subscribe_mode(mode) when mode in @subscribe_modes, do: :ok defp validate_subscribe_mode(_mode), do: :error + defp validate_tracks(tracks) when is_list(tracks), do: :ok + defp validate_tracks(_tracks), do: {:error, :tracks_validation} + defp map_snake_case_to_camel_case(%{} = map), do: Map.new(map, fn {k, v} -> {snake_case_to_camel_case(k), map_snake_case_to_camel_case(v)} end) diff --git a/test/jellyfish/hls_test.exs b/test/jellyfish/hls_test.exs deleted file mode 100644 index a763abb..0000000 --- a/test/jellyfish/hls_test.exs +++ /dev/null @@ -1,55 +0,0 @@ -defmodule Jellyfish.HLSTest do - use ExUnit.Case - - alias Jellyfish.{Client, Component, HLS, Room} - - @max_peers 10 - @video_codec :h264 - - @valid_tracks ["track-id"] - @invalid_tracks %{id: "track-id"} - @wrong_room_id "wrong-id" - - setup do - client = Client.new() - - {:ok, %Jellyfish.Room{id: id}, _jellyfish_address} = - Room.create(client, max_peers: @max_peers, video_codec: @video_codec) - - %{client: client, room_id: id} - end - - describe "HLS.subscribe/3" do - test "when request is valid", %{client: client, room_id: room_id} do - assert {:ok, %Component{metadata: %{subscribe_mode: "manual"}}} = - Room.add_component(client, room_id, %Component.HLS{subscribe_mode: :manual}) - - assert :ok = HLS.subscribe(client, room_id, @valid_tracks) - end - - test "when room doesn't exist", %{client: client} do - assert {:error, "Request failed: Room #{@wrong_room_id} does not exist"} = - HLS.subscribe(client, @wrong_room_id, @valid_tracks) - end - - test "when hls component doesn't exist", %{client: client, room_id: room_id} do - assert {:error, "Request failed: HLS component does not exist"} = - HLS.subscribe(client, room_id, @valid_tracks) - end - - test "when hls component has subscribe mode :auto", %{client: client, room_id: room_id} do - assert {:ok, %Component{metadata: %{subscribe_mode: "auto"}}} = - Room.add_component(client, room_id, %Jellyfish.Component.HLS{subscribe_mode: :auto}) - - assert {:error, "Request failed: HLS component option `subscribe_mode` is set to :auto"} = - HLS.subscribe(client, room_id, @valid_tracks) - end - - test "when request is invalid", %{client: client, room_id: room_id} do - assert {:ok, %Component{metadata: %{subscribe_mode: "manual"}}} = - Room.add_component(client, room_id, %Component.HLS{subscribe_mode: :manual}) - - assert {:error, :tracks_validation} = HLS.subscribe(client, room_id, @invalid_tracks) - end - end -end diff --git a/test/jellyfish/room_test.exs b/test/jellyfish/room_test.exs index bf06a61..6d0a57a 100644 --- a/test/jellyfish/room_test.exs +++ b/test/jellyfish/room_test.exs @@ -41,6 +41,9 @@ defmodule Jellyfish.RoomTest do @invalid_max_peers "abc" @invalid_video_codec :opus + @tracks ["track-id"] + @invalid_tracks %{id: "track-id"} + @invalid_peer_id "invalid_peer_id" defmodule InvalidPeerOpts do defstruct [:qwe, :rty] @@ -261,6 +264,42 @@ defmodule Jellyfish.RoomTest do end end + describe "Room.hls_subscribe/3" do + setup [:create_room] + + test "when request is valid", %{client: client, room_id: room_id} do + assert {:ok, %Component{metadata: %{subscribe_mode: "manual"}}} = + Room.add_component(client, room_id, %Component.HLS{subscribe_mode: :manual}) + + assert :ok = Room.hls_subscribe(client, room_id, @tracks) + end + + test "when room doesn't exist", %{client: client} do + assert {:error, "Request failed: Room #{@invalid_room_id} does not exist"} = + Room.hls_subscribe(client, @invalid_room_id, @tracks) + end + + test "when hls component doesn't exist", %{client: client, room_id: room_id} do + assert {:error, "Request failed: HLS component does not exist"} = + Room.hls_subscribe(client, room_id, @tracks) + end + + test "when hls component has subscribe mode :auto", %{client: client, room_id: room_id} do + assert {:ok, %Component{metadata: %{subscribe_mode: "auto"}}} = + Room.add_component(client, room_id, %Jellyfish.Component.HLS{subscribe_mode: :auto}) + + assert {:error, "Request failed: HLS component option `subscribe_mode` is set to :auto"} = + Room.hls_subscribe(client, room_id, @tracks) + end + + test "when request is invalid", %{client: client, room_id: room_id} do + assert {:ok, %Component{metadata: %{subscribe_mode: "manual"}}} = + Room.add_component(client, room_id, %Component.HLS{subscribe_mode: :manual}) + + assert {:error, :tracks_validation} = Room.hls_subscribe(client, room_id, @invalid_tracks) + end + end + defp create_room(state) do assert {:ok, %Jellyfish.Room{id: id}, _jellyfish_address} = Room.create(state.client, max_peers: @max_peers, video_codec: @video_codec)