-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add source dispatcher * configure CI to run tests
- Loading branch information
Showing
13 changed files
with
385 additions
and
157 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,43 @@ | ||
version: 2.1 | ||
|
||
jobs: | ||
build_test: | ||
docker: | ||
- image: membraneframeworklabs/docker_membrane | ||
steps: | ||
- checkout | ||
- run: | ||
command: | | ||
mix deps.get | ||
mix deps.compile | ||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./agora_sdk | ||
mix compile --force --warnings-as-errors | ||
orbs: | ||
elixir: membraneframework/elixir@1 | ||
|
||
workflows: | ||
version: 2 | ||
build: | ||
jobs: | ||
- build_test | ||
|
||
- elixir/build_test: | ||
# post-steps: # steps to run after steps defined in the job bar | ||
# - elixir/use_build_cache: | ||
# cache-version: 3 | ||
# env: test | ||
# regenerate: true | ||
# before-save: | ||
# - run: mix compile --force --warnings-as-errors | ||
filters: &filters | ||
tags: | ||
only: /v.*/ | ||
- elixir/test: | ||
pre-steps: # steps to run before steps defined in the job bar | ||
- checkout | ||
- elixir/get_mix_deps | ||
- run: | ||
command: mix compile --force | ||
filters: | ||
<<: *filters | ||
- elixir/lint: | ||
filters: | ||
<<: *filters | ||
docs: false | ||
- elixir/hex_publish: | ||
requires: | ||
- elixir/build_test | ||
- elixir/test | ||
- elixir/lint | ||
context: | ||
- Deployment | ||
filters: | ||
branches: | ||
ignore: /.*/ | ||
tags: | ||
only: /v.*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
defmodule Membrane.Agora.Dispatcher do | ||
@moduledoc """ | ||
This element allows for dispatching the streams received by the `Membrane.Agora.Source` | ||
based on the `user_id` field from the buffer's metadata. | ||
The `Membrane.Agora.Source` sends a single stream for all the users that are present in the | ||
Agora channel and enriches buffers with the `user_id` field which corresponds | ||
to the ID of the stream sender from the Agora channel. The `#{inspect(__MODULE__)}` element allows | ||
to demultiplex such a single output channel stream into multiple streams for each of the users. | ||
Usage: | ||
* attach the `#{inspect(__MODULE__)}` element to each output pad of the `Membrane.Agora.Source`. | ||
* when the `{:add_pad, <user_id>}` message is received from a given `#{inspect(__MODULE__)}` dispatcher, | ||
attach the output pad with the following name: `{:output, <user_id>}` to this particular dispatcher | ||
""" | ||
|
||
use Membrane.Filter | ||
|
||
require Logger | ||
require Membrane.Logger | ||
|
||
def_input_pad(:input, | ||
accepted_format: | ||
any_of( | ||
%Membrane.H264{alignment: :au}, | ||
%Membrane.RawAudio{sample_rate: 44_100, channels: 2, sample_format: :s16le} | ||
) | ||
) | ||
|
||
def_output_pad(:output, | ||
accepted_format: | ||
any_of( | ||
%Membrane.H264{alignment: :au}, | ||
%Membrane.RawAudio{sample_rate: 44_100, channels: 2, sample_format: :s16le} | ||
), | ||
availability: :on_request | ||
) | ||
|
||
def_options queue_before_pad_connected?: [ | ||
spec: boolean(), | ||
default: true, | ||
description: """ | ||
If true, the buffers will be queued until the corresponding pad, on which they should be sent, is connected. | ||
Otherwise, if there is no corresponding pad available, the buffers are discarded. | ||
Defaults to true. | ||
""" | ||
] | ||
|
||
@impl true | ||
def handle_init(_ctx, opts) do | ||
{[], | ||
%{ | ||
output_pads: %{}, | ||
queue_before_pad_connected?: opts.queue_before_pad_connected?, | ||
stream_format: nil | ||
}} | ||
end | ||
|
||
@impl true | ||
def handle_stream_format(:input, format, _ctx, state) do | ||
{[forward: format], %{state | stream_format: format}} | ||
end | ||
|
||
@impl true | ||
def handle_buffer(:input, buffer, _ctx, state) do | ||
user_id = buffer.metadata.id | ||
|
||
cond do | ||
user_id not in Map.keys(state.output_pads) -> | ||
state = add_pad(state, user_id) | ||
state = buffer_up(state, buffer) | ||
{[notify_parent: {:add_pad, user_id}], state} | ||
|
||
state.output_pads[user_id].is_connected -> | ||
{[buffer: {Pad.ref(:output, user_id), buffer}], state} | ||
|
||
true -> | ||
state = buffer_up(state, buffer) | ||
{[], state} | ||
end | ||
end | ||
|
||
@impl true | ||
def handle_pad_added(Pad.ref(:output, user_id), _ctx, state) do | ||
{notify_child_actions, state} = | ||
if user_id in Map.keys(state.output_pads) do | ||
{[], state} | ||
else | ||
{[], add_pad(state, user_id)} | ||
end | ||
|
||
state = | ||
update_in(state, [:output_pads, user_id, :is_connected], fn false -> | ||
true | ||
end) | ||
|
||
stream_format_actions = | ||
if state.stream_format, | ||
do: [stream_format: {Pad.ref(:output, user_id), state.stream_format}], | ||
else: [] | ||
|
||
buffer_actions = | ||
Enum.reverse(state.output_pads[user_id].buffered) | ||
|> Enum.map(&{Pad.ref(:output, user_id), &1}) | ||
|
||
{notify_child_actions ++ stream_format_actions ++ buffer_actions, state} | ||
end | ||
|
||
defp add_pad(state, user_id) do | ||
put_in(state, [:output_pads, user_id], %{buffered: [], is_connected: false}) | ||
end | ||
|
||
defp buffer_up(%{queue_before_pad_connected?: true} = state, _buffer) do | ||
state | ||
end | ||
|
||
defp buffer_up(state, buffer) do | ||
user_id = buffer.metadata.id | ||
|
||
update_in(state, [:output_pads, user_id, :buffered], fn buffered -> | ||
[buffer | buffered] | ||
end) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.