Skip to content

Commit cae7542

Browse files
committed
Add rtsp config section
1 parent 3600d79 commit cae7542

6 files changed

Lines changed: 109 additions & 44 deletions

File tree

config/test.exs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@ config :shinkai, :server, enabled: false
66

77
config :shinkai, :rtmp, port: 0
88

9+
config :shinkai, :rtsp, enabled: false
10+
911
config :shinkai, :hls, storage_dir: "tmp"

lib/shinkai.ex

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,7 @@ defmodule Shinkai do
1515
1616
To configure the http server responsible for serving HLS streams.
1717
18-
* `enabled` - Enable or disable the HTTP server.
19-
* `port` - Port number for the HTTP server.
20-
* `certfile` - Path to the SSL certificate file (optional).
21-
* `keyfile` - Path to the SSL key file (optional).
18+
#{NimbleOptions.docs(Shinkai.Config.server_schema())}
2219
2320
```elixir
2421
config :shinkai, :server,
@@ -40,12 +37,7 @@ defmodule Shinkai do
4037
4138
To configure HLS streaming options.
4239
43-
* `storage_dir` - Directory to store HLS segments.
44-
* `max_segments` - Maximum number of segments to keep.
45-
* `segment_duration` - Segment duration in milliseconds.
46-
* `part_duration` - Part duration in milliseconds.
47-
* `segment_type` - Type of segments to generate, either `fmp4`,
48-
`mpeg_ts`, or `low_latency`.
40+
#{NimbleOptions.docs(Shinkai.Config.hls_schema())}
4941
5042
```elixir
5143
config :shinkai, :hls,
@@ -66,8 +58,8 @@ defmodule Shinkai do
6658
### RTMP
6759
6860
To configure the RTMP server.
69-
* `enabled` - Enable or disable the RTMP server.
70-
* `port` - Port number for the RTMP server.
61+
62+
#{NimbleOptions.docs(Shinkai.Config.rtmp_schema())}
7163
7264
```elixir
7365
config :shinkai, :rtmp,
@@ -81,6 +73,24 @@ defmodule Shinkai do
8173
port: 1935 # Port number for the RTMP server (default: 1935)
8274
```
8375
76+
### RTSP
77+
78+
To configure the RTSP server.
79+
80+
#{NimbleOptions.docs(Shinkai.Config.rtsp_schema())}
81+
82+
```elixir
83+
config :shinkai, :rtsp,
84+
enabled: true,
85+
port: 8554
86+
```
87+
88+
```yaml
89+
rtsp:
90+
enabled: true # Enable or disable the RTSP server (default: true)
91+
port: 8554 # Port number for the RTSP server (default: 8554)
92+
```
93+
8494
### Paths
8595
8696
To configure media source paths. Each source should have a unique alphanumeric ID.

lib/shinkai/application.ex

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ defmodule Shinkai.Application do
1616
{Sources.PublishManager, []},
1717
{Registry, name: Sink.Registry, keys: :duplicate},
1818
{Registry, name: Source.Registry, keys: :unique},
19-
{Task, fn -> Sources.start_all() end},
20-
{RTSP.Server, handler: Sources.RTSP.Handler, port: 8554}
19+
{Task, fn -> Sources.start_all() end}
2120
]
2221

2322
children =
@@ -27,6 +26,13 @@ defmodule Shinkai.Application do
2726
children
2827
end
2928

29+
children =
30+
if config[:rtsp][:enabled] do
31+
children ++ [{RTSP.Server, handler: Sources.RTSP.Handler, port: config[:rtsp][:port]}]
32+
else
33+
children
34+
end
35+
3036
children =
3137
if Code.ensure_loaded?(Bandit) and config[:server][:enabled] do
3238
children ++ [{Bandit, configure_bandit(config[:server])}]

lib/shinkai/config.ex

Lines changed: 65 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ defmodule Shinkai.Config do
33

44
use GenServer
55

6-
@top_level_keys [:rtmp, :server, :hls]
6+
@top_level_keys [:rtmp, :server, :hls, :rtsp]
77

88
@rtmp_schema [
99
enabled: [
@@ -14,7 +14,24 @@ defmodule Shinkai.Config do
1414
port: [
1515
type: {:in, 0..(2 ** 16 - 1)},
1616
default: 1935,
17-
doc: "RTMP listening port"
17+
doc: "RTMP listening port",
18+
type_doc: "`t::socket.port_number/0`",
19+
type_spec: quote do: :socket.port_number()
20+
]
21+
]
22+
23+
@rtsp_schema [
24+
enabled: [
25+
type: :boolean,
26+
default: true,
27+
doc: "Enable or disable rtsp"
28+
],
29+
port: [
30+
type: {:in, 0..(2 ** 16 - 1)},
31+
default: 8554,
32+
doc: "RTSP listening port",
33+
type_doc: "`t::socket.port_number/0`",
34+
type_spec: quote do: :socket.port_number()
1835
]
1936
]
2037

@@ -27,7 +44,9 @@ defmodule Shinkai.Config do
2744
port: [
2845
type: {:in, 0..(2 ** 16 - 1)},
2946
default: 8888,
30-
doc: "http port"
47+
doc: "http port",
48+
type_doc: "`t::socket.port_number/0`",
49+
type_spec: quote do: :socket.port_number()
3150
],
3251
certfile: [
3352
type: {:or, [:string, nil]},
@@ -44,7 +63,8 @@ defmodule Shinkai.Config do
4463
@hls_schema [
4564
storage_dir: [
4665
type: :string,
47-
default: "/tmp/shinkai/hls"
66+
default: "/tmp/shinkai/hls",
67+
doc: "Directory to store HLS segments"
4868
],
4969
max_segments: [
5070
type: :non_neg_integer,
@@ -53,18 +73,37 @@ defmodule Shinkai.Config do
5373
],
5474
segment_duration: [
5575
type: :non_neg_integer,
56-
default: 2000
76+
default: 2000,
77+
doc: "Segment duration in milliseconds"
5778
],
5879
part_duration: [
5980
type: :non_neg_integer,
60-
default: 300
81+
default: 300,
82+
doc: "Part duration in milliseconds for low-latency HLS"
6183
],
6284
segment_type: [
6385
type: {:custom, __MODULE__, :validate_hls_segment_type, []},
64-
default: :fmp4
86+
default: :fmp4,
87+
doc: "Type of segments to generate, either `:fmp4`, `:mpeg_ts` or `:low_latency`"
6588
]
6689
]
6790

91+
@doc false
92+
@spec server_schema() :: keyword()
93+
def server_schema, do: @server_schema
94+
95+
@doc false
96+
@spec rtmp_schema() :: keyword()
97+
def rtmp_schema, do: @rtmp_schema
98+
99+
@doc false
100+
@spec hls_schema() :: keyword()
101+
def hls_schema, do: @hls_schema
102+
103+
@doc false
104+
@spec rtsp_schema() :: keyword()
105+
def rtsp_schema, do: @rtsp_schema
106+
68107
def start_link(config) do
69108
GenServer.start_link(__MODULE__, config, name: __MODULE__)
70109
end
@@ -88,10 +127,15 @@ defmodule Shinkai.Config do
88127

89128
app_configs = Enum.map(@top_level_keys, &{&1, Application.get_env(:shinkai, &1, [])})
90129

91-
Enum.map(@top_level_keys, fn key ->
92-
[]
93-
|> Keyword.merge(app_configs[key])
94-
|> Keyword.merge(user_config[key])
130+
app_configs =
131+
@top_level_keys
132+
|> Enum.map(&{&1, []})
133+
|> Keyword.merge(app_configs)
134+
|> parse_and_validate()
135+
136+
Enum.map(app_configs, fn {key, config} ->
137+
config
138+
|> Keyword.merge(user_config[key] || [])
95139
|> then(&{key, &1})
96140
end)
97141
end
@@ -120,9 +164,7 @@ defmodule Shinkai.Config do
120164

121165
case Map.keys(config) -- keys do
122166
[] ->
123-
@top_level_keys
124-
|> Enum.map(&{&1, []})
125-
|> Keyword.merge(Enum.map(config, fn {key, value} -> {String.to_atom(key), value} end))
167+
Enum.map(config, fn {key, value} -> {String.to_atom(key), value} end)
126168

127169
invalid_keys ->
128170
raise ArgumentError, """
@@ -137,19 +179,16 @@ defmodule Shinkai.Config do
137179

138180
defp parse_and_validate([], acc), do: acc
139181

140-
defp parse_and_validate([{:hls, hls_config} | rest], acc) do
141-
hls_config = do_parse_and_validate(hls_config, @hls_schema)
142-
parse_and_validate(rest, [{:hls, hls_config} | acc])
143-
end
144-
145-
defp parse_and_validate([{:server, server_config} | rest], acc) do
146-
server_config = do_parse_and_validate(server_config, @server_schema)
147-
parse_and_validate(rest, [{:server, server_config} | acc])
148-
end
182+
defp parse_and_validate([{key, config} | rest], acc) do
183+
config =
184+
case key do
185+
:hls -> do_parse_and_validate(config, @hls_schema)
186+
:server -> do_parse_and_validate(config, @server_schema)
187+
:rtmp -> do_parse_and_validate(config, @rtmp_schema)
188+
:rtsp -> do_parse_and_validate(config, @rtsp_schema)
189+
end
149190

150-
defp parse_and_validate([{:rtmp, rtmp_config} | rest], acc) do
151-
rtmp_config = do_parse_and_validate(rtmp_config, @rtmp_schema)
152-
parse_and_validate(rest, [{:rtmp, rtmp_config} | acc])
191+
parse_and_validate(rest, [{key, config} | acc])
153192
end
154193

155194
defp do_parse_and_validate(config, schema) do

test/shinkai/config_test.exs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ defmodule Shinkai.ConfigTest do
1515

1616
config = Config.validate(user_config)
1717

18-
assert Keyword.keys(config) == [:rtmp, :server, :hls]
18+
assert Keyword.keys(config) |> Enum.sort() == [:hls, :rtmp, :rtsp, :server]
1919

2020
assert %{
2121
segment_type: :low_latency,
@@ -26,7 +26,7 @@ defmodule Shinkai.ConfigTest do
2626
} == Map.new(config[:hls])
2727

2828
assert %{
29-
enabled: true,
29+
enabled: false,
3030
port: 8888,
3131
certfile: nil,
3232
keyfile: nil

test/shinkai/pipeline_test.exs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ defmodule Shinkai.PipelineTest do
1414
"test/fixtures/big_buck_avc_aac.mp4"
1515
]
1616

17+
setup do
18+
{:ok, rtsp_server} = RTSP.Server.start_link(port: 0, handler: Shinkai.Sources.RTSP.Handler)
19+
{:ok, rtsp_server: rtsp_server}
20+
end
21+
1722
for fixture <- @fixtures do
1823
describe "hls sink: #{fixture}" do
1924
test "Stream from rtsp" do
@@ -38,11 +43,14 @@ defmodule Shinkai.PipelineTest do
3843
on_exit(fn -> File.rm_rf!(hls_path) end)
3944
end
4045

41-
test "Stream from rtsp publish", %{tmp_dir: _dir} do
46+
test "Stream from rtsp publish", %{rtsp_server: server} do
4247
id = UUID.uuid4()
4348
Phoenix.PubSub.subscribe(Shinkai.PubSub, Utils.sink_topic(id))
4449

45-
Publisher.new("rtsp://localhost:8554/#{id}", unquote(fixture))
50+
{:ok, port} = RTSP.Server.port_number(server)
51+
52+
"rtsp://localhost:#{port}/#{id}"
53+
|> Publisher.new(unquote(fixture))
4654
|> Publisher.publish()
4755

4856
assert_receive {:hls, :done}, 5_000

0 commit comments

Comments
 (0)