Skip to content

Commit

Permalink
Docs and examples improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
mat-hek committed Oct 1, 2024
1 parent 6bcb3e1 commit 39ef476
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 170 deletions.
59 changes: 0 additions & 59 deletions examples/assets/browser_to_file/browser_to_file.js

This file was deleted.

35 changes: 25 additions & 10 deletions examples/assets/browser_to_file/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,34 @@
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Membrane WebRTC browser to file example</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Membrane WebRTC WHIP/WHEP Example</title>
</head>

<body
style="background-color: black; color: white; font-family: Arial, Helvetica, sans-serif; min-height: 100vh; margin: 0px; padding: 5px 0px 5px 0px">
<main>
<h1>Membrane WebRTC browser to file example</h1>
<div id="status">Connecting</div>
</main>
<script src="browser_to_file.js"></script>
style="background-color: black; color: white; font-family: Arial, Helvetica, sans-serif; min-height: 100vh; margin: 0px; padding: 5px 0px 5px 0px">
<h1>Membrane WebRTC WHIP/WHEP Example</h1>
<div id="status">Connecting...</div>
<script type="module">
import { WHIPClient } from 'https://cdn.jsdelivr.net/npm/[email protected]/whip.js'

const status = document.getElementById("status");
const pcConfig = { iceServers: [{ urls: "stun:stun.l.google.com:19302" }] };
const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true });
const pc = new RTCPeerConnection(pcConfig);
for (const track of stream.getTracks()) { pc.addTransceiver(track, { 'direction': 'sendonly' }) }
const whip = new WHIPClient();
const url = "http://localhost:8829/";
const token = "whip_it!";
await whip.publish(pc, url, token);
status.innerHTML = "Connected <button id='disconnect'>Disconnect</button>"
document.getElementById("disconnect").onclick = () => {
status.innerHTML = "Disconnected";
whip.stop();
}
</script>
</body>

</html>
44 changes: 0 additions & 44 deletions examples/assets/whip.html

This file was deleted.

67 changes: 16 additions & 51 deletions examples/browser_to_file.exs
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,16 @@ defmodule Example.Pipeline do

@impl true
def handle_init(_ctx, opts) do
# p = self()

# Membrane.WebRTC.WhipServer.start_link(
# port: 8888,
# handle_new_client: fn signaling, _token ->
# send(p, {:ready, signaling})
# :ok
# end
# )

# signaling = receive do: ({:ready, signaling} -> signaling)

spec =
[
child(:webrtc, %WebRTC.Source{
# signaling: {:whip, port: opts[:port], ip: :any, serve_static: "examples/assets"}
signaling: opts[:port]
signaling: {
:whip,
token: "whip_it!",
port: opts[:port],
ip: :any,
serve_static: "#{__DIR__}/assets/browser_to_file"
}
}),
child(:matroska, Membrane.Matroska.Muxer),
get_child(:webrtc)
Expand Down Expand Up @@ -67,43 +60,15 @@ defmodule Example.Pipeline do
end
end

defmodule Router do
use Plug.Router

plug(Plug.Logger)
plug(Plug.Static, at: "/", from: "examples/assets")
plug(:match)
plug(:dispatch)

forward(
"/",
to: Membrane.WebRTC.WhipServer.Router,
handle_new_client: &__MODULE__.handle_new_client/1
)

def handle_new_client(_token) do
signaling = Membrane.WebRTC.SignalingChannel.new()
port = 8829
{:ok, supervisor, _pipeline} = Membrane.Pipeline.start_link(Example.Pipeline, port: port)
Process.monitor(supervisor)

{:ok, _supervisor, _pipeline} =
Membrane.Pipeline.start_link(Example.Pipeline, port: signaling)
Logger.info("""
Visit http://localhost:#{port}/static/index.html to start the stream. To finish the recording properly,
don't terminate this script - instead click 'disconnect' in the website or close the browser tab.
""")

{:ok, signaling}
end
receive do
{:DOWN, _ref, :process, ^supervisor, _reason} -> :ok
end

Bandit.start_link(plug: Router, ip: :any, port: 8829)

Process.sleep(:infinity)

# port = 8829
# {:ok, supervisor, _pipeline} = Membrane.Pipeline.start_link(Example.Pipeline, port: port)
# Process.monitor(supervisor)

# Logger.info("""
# Visit http://localhost:#{port}/index.html to start the stream. To finish the recording properly,
# don't terminate this script - instead click 'disconnect' in the website or close the browser tab.
# """)

# receive do
# {:DOWN, _ref, :process, ^supervisor, _reason} -> :ok
# end
13 changes: 9 additions & 4 deletions lib/membrane_webrtc/ex_webrtc/source.ex
Original file line number Diff line number Diff line change
Expand Up @@ -366,10 +366,15 @@ defmodule Membrane.WebRTC.ExWebRTCSource do
defp setup_whip(ctx, opts) do
signaling = SignalingChannel.new()
clients_cnt = :atomics.new(1, [])

handle_new_client = fn _token ->
clients_cnt = :atomics.add_get(clients_cnt, 1, 1)
if clients_cnt == 1, do: {:ok, signaling}, else: {:error, :already_connected}
{token, opts} = Keyword.pop(opts, :token, fn _token -> true end)
validate_token = if is_function(token), do: token, else: &(&1 == token)

handle_new_client = fn token ->
cond do
!validate_token.(token) -> {:error, :invalid_token}
:atomics.add_get(clients_cnt, 1, 1) > 1 -> {:error, :already_connected}
true -> {:ok, signaling}
end
end

Membrane.UtilitySupervisor.start_child(ctx.utility_supervisor, {
Expand Down
14 changes: 13 additions & 1 deletion lib/membrane_webrtc/sink.ex
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,24 @@ defmodule Membrane.WebRTC.Sink do
"""
@type new_tracks :: {:new_tracks, [%{id: term, kind: :audio | :video}]}

@typedoc """
WHIP client options
- `uri` - Address of the WHIP server (HTTP/HTTPS)
- `token` - WHIP token, defaults to an empty string
"""
@type whip_options :: {:uri, String.t()} | {:token, String.t()}

def_options signaling: [
spec: SignalingChannel.t() | {:websocket, SimpleWebSocketServer.options()},
spec:
SignalingChannel.t()
| {:whip, whip_options}
| {:websocket, SimpleWebSocketServer.options()},
description: """
Channel for passing WebRTC signaling messages (SDP and ICE).
Either:
- `#{inspect(SignalingChannel)}` - See its docs for details.
- `{:whip, options}` - Acts as a WHIP client, see `t:whip_options/0` for details.
- `{:websocket, options}` - Spawns #{inspect(SimpleWebSocketServer)},
see there for details.
"""
Expand Down
22 changes: 21 additions & 1 deletion lib/membrane_webrtc/source.ex
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,32 @@ defmodule Membrane.WebRTC.Source do
"""
@type new_tracks :: {:new_tracks, [%{id: term, kind: :audio | :video}]}

@typedoc """
Options for WHIP server input.
The server accepts a single connection and the stream is received by this source. The options are:
- `token` - either expected WHIP token or a function returning true if the token is valid, otherwise false
- `serve_static` - make WHIP server also serve static content, such as an HTML page under `/static` endpoint
- Any of `t:Bandit.options/0` - in particular `ip` and `port`
To handle multiple connections and have more control over the server, see `Membrane.WebRTC.WhipServer`.
"""
@type whip_options ::
{:token, String.t() | (String.t() -> boolean())}
| {:serve_static, String.t()}
| {atom, term()}

def_options signaling: [
spec: SignalingChannel.t() | {:websocket, SimpleWebSocketServer.options()},
spec:
SignalingChannel.t()
| {:whip, whip_options()}
| {:websocket, SimpleWebSocketServer.options()},
description: """
Channel for passing WebRTC signaling messages (SDP and ICE).
Either:
- `#{inspect(SignalingChannel)}` - See its docs for details.
- `{:whip, options}` - Starts a WHIP server, see `t:whip_options/0` for details.
- `{:websocket, options}` - Spawns #{inspect(SimpleWebSocketServer)},
see there for details.
"""
Expand Down

0 comments on commit 39ef476

Please sign in to comment.