Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send keyframe request #20

Closed
wants to merge 34 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
68648b3
Move sample local user observer to the common directory. Add send_key…
varsill Jul 4, 2024
97c61f7
Send event in the membrane element
varsill Jul 4, 2024
3f34572
Add missing field and constructor
varsill Jul 4, 2024
53c90ba
Update bundlex config
varsill Jul 4, 2024
fd0fe4b
Add missing include
varsill Jul 4, 2024
bf54a4e
Change spec of the signal.
varsill Jul 4, 2024
5566d9f
Move onIntraRequestReceived declaration to sample local user observer
varsill Jul 4, 2024
0338a2f
Add missing include
varsill Jul 4, 2024
5e3da34
Make environment constraints less strict
varsill Jul 4, 2024
b47b931
Add a sends spec to the source as a workaround
varsill Jul 5, 2024
55e2006
Add log
varsill Jul 5, 2024
81acea6
Register local user observer. Add elixir log
varsill Jul 5, 2024
09b0b6c
Fix typo
varsill Jul 5, 2024
0ccfc68
Derefer the shared pointer
varsill Jul 5, 2024
34c8226
Make sure keyframe is requested only when playback is playing. Add pr…
varsill Jul 5, 2024
3a7f54f
Add debug log
varsill Jul 5, 2024
480f5e5
Change the pad name while requesting for keyframe
varsill Jul 5, 2024
1cd55de
Remove the resetting of the localUserObserver
varsill Jul 5, 2024
e4e1848
fix segfault with connection being empty in the source
varsill Jul 5, 2024
c345662
Disable local user observer
varsill Jul 5, 2024
d551273
Create user observer
varsill Jul 5, 2024
cd2ca09
Make sure local user observer is unregistered
varsill Jul 5, 2024
56b7657
Pass localUser in the constructor
varsill Jul 5, 2024
8e193c8
Add localUserObserver to sink's state
varsill Jul 5, 2024
b369a25
Add localUserObserver to sink's state
varsill Jul 5, 2024
2ef6aa5
Don't use sample local user observer in source
varsill Jul 8, 2024
97d888d
Move sink setup to handle_playing
varsill Jul 8, 2024
5a44ae3
Send event on proper pad
varsill Jul 8, 2024
6d10464
Update dependency to file plugin
varsill Jul 8, 2024
d6066e0
Store connObserver in state
varsill Jul 8, 2024
ba4bcf0
Change connObserver type to ConnectionObserver
varsill Jul 8, 2024
dd642c8
Remove unused code. Update deps
varsill Jul 9, 2024
d7baa4a
Remove unused deps
varsill Jul 9, 2024
4359689
Use INFO log level to inform about keyframe request
varsill Jul 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions bundlex.exs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ defmodule Membrane.Agora.BundlexProject do
]
end

defp natives(%{architecture: "x86_64", os: "linux"}) do
defp natives(%{os: "linux"}) do
unless System.get_env("AGORA_SDK_PRESENT") == "true", do: System.shell("./install.sh")

[
sink: [
sources: ["sink.cpp", "connection_observer.cpp"],
sources: ["sink.cpp", "connection_observer.cpp", "sample_local_user_observer.cpp"],
includes: ["agora_sdk/include/"],
libs: ["agora_rtc_sdk", "agora-ffmpeg"],
lib_dirs: ["agora_sdk/"],
Expand All @@ -27,7 +27,7 @@ defmodule Membrane.Agora.BundlexProject do
"connection_observer.cpp",
"source/sample_audio_frame_observer.cpp",
"source/sample_video_encoded_frame_observer.cpp",
"source/sample_local_user_observer.cpp"
"sample_local_user_observer.cpp"
],
includes: ["agora_sdk/include/"],
libs: ["agora_rtc_sdk", "agora-ffmpeg"],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#include "./_generated/sink.h"
#include "sample_local_user_observer.h"
#include "common.h"

void SampleLocalUserObserver::onAudioTrackPublishSuccess(
agora_refptr<ILocalAudioTrack> audioTrack) {}
Expand Down Expand Up @@ -71,3 +73,12 @@ void SampleLocalUserObserver::onVideoTrackUnpublished(agora_refptr<ILocalVideoTr
void SampleLocalUserObserver::onVideoTrackPublishStart(agora_refptr<ILocalVideoTrack> videoTrack) {}
void SampleLocalUserObserver::onAudioTrackUnpublished(agora_refptr<ILocalAudioTrack> audioTrack) {}
void SampleLocalUserObserver::onAudioTrackPublishStart(agora_refptr<ILocalAudioTrack> audioTrack) {}
void SampleLocalUserObserver::onIntraRequestReceived() {
AG_LOG(INFO, "Keyframe request received");

if (_destination.has_value()) {
UnifexEnv *env = unifex_alloc_env(NULL);
send_keyframe_request(env, _destination.value(), UNIFEX_SEND_THREADED);
unifex_free_env(env);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include <unifex/unifex.h>
#include <optional>
#include "AgoraBase.h"
#include "NGIAgoraLocalUser.h"

Expand All @@ -8,8 +10,13 @@ using namespace agora::rtc;

class SampleLocalUserObserver : public ILocalUserObserver {
public:
SampleLocalUserObserver() {}
~SampleLocalUserObserver() {}
SampleLocalUserObserver(): _destination(std::nullopt){}
SampleLocalUserObserver(ILocalUser *localUser, UnifexPid destination): _localUser(localUser), _destination(destination) {
_localUser->registerLocalUserObserver(this);
}
~SampleLocalUserObserver() {
_localUser->unregisterLocalUserObserver(this);
}
void onAudioTrackPublishSuccess(
agora_refptr<ILocalAudioTrack> audioTrack) override;
void onLocalAudioTrackStatistics(const LocalAudioStats &stats) override;
Expand Down Expand Up @@ -82,4 +89,9 @@ class SampleLocalUserObserver : public ILocalUserObserver {
void onVideoTrackPublishStart(agora_refptr<ILocalVideoTrack> videoTrack) override;
void onAudioTrackUnpublished(agora_refptr<ILocalAudioTrack> audioTrack) override;
void onAudioTrackPublishStart(agora_refptr<ILocalAudioTrack> audioTrack) override;
void onIntraRequestReceived() override;

private:
std::optional<UnifexPid> _destination;
ILocalUser *_localUser;
};
17 changes: 10 additions & 7 deletions c_src/membrane_agora_plugin/sink.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "sink.h"
#include "sample_local_user_observer.h"

// Once SIGINT is delivered twice to the process that runs the elixir script
// (e.g. with ctrl+c), the script terminates. Sometimes it results in a
Expand All @@ -7,7 +8,7 @@
// SIGTERM.

UNIFEX_TERM create(UnifexEnv *env, char *appId, char *token, char *channelId,
char *userId) {
char *userId, UnifexPid destination) {

// sink's native state initialization
SinkState *state = unifex_alloc_state(env);
Expand Down Expand Up @@ -41,17 +42,17 @@ UNIFEX_TERM create(UnifexEnv *env, char *appId, char *token, char *channelId,
s->setBool("che.video.has_intra_request", false);

// connecting
auto connObserver = std::make_shared<ConnectionObserver>(state->connection);
state->connection->registerObserver(connObserver.get());
state->connObserver = std::make_shared<ConnectionObserver>(state->connection);
state->connection->registerObserver(state->connObserver.get());

int connection_res = state->connection->connect(token, channelId, userId);
if (connection_res) {
AG_LOG(ERROR, "Failed to connect to Agora channel!");
unifex_release_state(env, state);
return create_result_error(env, "Failed to connect to Agora channel!");
}
connObserver->waitUntilConnected();

state->localUserObserver = std::make_shared<SampleLocalUserObserver>(state->connection->getLocalUser(), destination);
// senders creation
agora::agora_refptr<agora::rtc::IMediaNodeFactory> factory =
state->service->createMediaNodeFactory();
Expand Down Expand Up @@ -99,10 +100,8 @@ UNIFEX_TERM create(UnifexEnv *env, char *appId, char *token, char *channelId,
state->customAudioTrack->setEnabled(true);
state->connection->getLocalUser()->publishVideo(state->customVideoTrack);
state->connection->getLocalUser()->publishAudio(state->customAudioTrack);
state->connObserver->waitUntilConnected();

// cleaning up
state->connection->unregisterObserver(connObserver.get());
connObserver.reset();
UNIFEX_TERM res = create_result_ok(env, state);
unifex_release_state(env, state);

Expand Down Expand Up @@ -170,6 +169,10 @@ UNIFEX_TERM write_audio_data(UnifexEnv *env, UnifexPayload *payload,
void handle_destroy_state(UnifexEnv *env, SinkState *state) {
UNUSED(env);
if (state->connection) {
// cleaning up
state->connection->unregisterObserver(state->connObserver.get());
state->connObserver.reset();
state->localUserObserver.reset();
if (state->customVideoTrack) {
state->connection->getLocalUser()->unpublishVideo(
state->customVideoTrack);
Expand Down
3 changes: 3 additions & 0 deletions c_src/membrane_agora_plugin/sink.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "NGIAgoraMediaNodeFactory.h"
#include "NGIAgoraRtcConnection.h"
#include "NGIAgoraVideoTrack.h"
#include "NGIAgoraLocalUser.h"

#include "common.h"
#include "connection_observer.h"
Expand All @@ -28,6 +29,8 @@ typedef struct {
audioEncodedFrameSender;
agora::agora_refptr<agora::rtc::ILocalVideoTrack> customVideoTrack;
agora::agora_refptr<agora::rtc::ILocalAudioTrack> customAudioTrack;
std::shared_ptr<ConnectionObserver> connObserver;
std::shared_ptr<ILocalUserObserver> localUserObserver;

// video track parameters
unsigned int width;
Expand Down
4 changes: 3 additions & 1 deletion c_src/membrane_agora_plugin/sink.spec.exs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ spec(
app_id :: string,
token :: string,
channel_id :: string,
user_id :: string
user_id :: string,
destination :: pid
) :: {:ok :: label, state} | {:error :: label, reason :: atom}
)

Expand Down Expand Up @@ -38,5 +39,6 @@ spec(

sends {:user_joined :: label, id :: string}
sends {:user_left :: label, id :: string}
sends :keyframe_request :: label

dirty :cpu, [:create, :write_video_data, :update_video_stream_format, :write_audio_data, :update_audio_stream_format]
29 changes: 10 additions & 19 deletions c_src/membrane_agora_plugin/source.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "source.h"
#include "source/sample_audio_frame_observer.h"
#include "source/sample_local_user_observer.h"
#include "source/sample_video_encoded_frame_observer.h"
#include "sample_local_user_observer.h"

UNIFEX_TERM create(UnifexEnv *env, char *appId, char *token, char *channelId,
char *userId, UnifexPid destination) {
Expand Down Expand Up @@ -52,15 +52,11 @@ UNIFEX_TERM create(UnifexEnv *env, char *appId, char *token, char *channelId,
state->connection->getLocalUser()->subscribeAllVideo(options);
state->connection->getLocalUser()->subscribeAllAudio();

state->localUserObserver = std::make_shared<SampleLocalUserObserver>();
state->videoEncodedFrameObserver =
std::make_shared<SampleVideoEncodedFrameObserver>(destination);
state->audioFrameObserver =
std::make_shared<SampleAudioFrameObserver>(destination);

state->connection->getLocalUser()->registerLocalUserObserver(
state->localUserObserver.get());

state->connection->getLocalUser()->registerVideoEncodedFrameObserver(
state->videoEncodedFrameObserver.get());

Expand All @@ -77,22 +73,17 @@ UNIFEX_TERM create(UnifexEnv *env, char *appId, char *token, char *channelId,
}

void handle_destroy_state(UnifexEnv *env, SourceState *state) {
state->connection->unregisterObserver(state->connObserver.get());
state->connObserver.reset();

state->connection->getLocalUser()->unregisterLocalUserObserver(
state->localUserObserver.get());
state->connection->getLocalUser()->unregisterVideoEncodedFrameObserver(
state->videoEncodedFrameObserver.get());
state->connection->getLocalUser()->unregisterAudioFrameObserver(
state->audioFrameObserver.get());

state->localUserObserver.reset();
state->videoEncodedFrameObserver.reset();
state->audioFrameObserver.reset();

UNUSED(env);
if (state->connection) {
state->connection->unregisterObserver(state->connObserver.get());
state->connObserver.reset();
state->connection->getLocalUser()->unregisterVideoEncodedFrameObserver(
state->videoEncodedFrameObserver.get());
state->connection->getLocalUser()->unregisterAudioFrameObserver(
state->audioFrameObserver.get());

state->videoEncodedFrameObserver.reset();
state->audioFrameObserver.reset();
if (state->connection->disconnect()) {
AG_LOG(ERROR, "Failed to disconnect from Agora channel!");
return;
Expand Down
1 change: 0 additions & 1 deletion c_src/membrane_agora_plugin/source.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ typedef struct {
agora::base::IAgoraService *service = NULL;
agora::agora_refptr<agora::rtc::IRtcConnection> connection;
std::shared_ptr<ConnectionObserver> connObserver;
std::shared_ptr<agora::rtc::ILocalUserObserver> localUserObserver;
std::shared_ptr<agora::media::IVideoEncodedFrameObserver>
videoEncodedFrameObserver;
std::shared_ptr<agora::media::IAudioFrameObserverBase> audioFrameObserver;
Expand Down
1 change: 1 addition & 0 deletions c_src/membrane_agora_plugin/source.spec.exs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ sends {:agora_audio_payload :: label, payload, id :: string}
sends {:agora_video_payload :: label, payload, id :: int}
sends {:user_joined :: label, id :: string}
sends {:user_left :: label, id :: string}
sends :keyframe_request :: label

dirty :cpu, [:create]
22 changes: 20 additions & 2 deletions lib/agora/agora_sink.ex
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ defmodule Membrane.Agora.Sink do
end

@impl true
def handle_setup(_ctx, state) do
def handle_playing(_ctx, state) do
{:ok, native_state} =
try do
Native.create(state.app_id, state.token, state.channel_name, state.user_id)
Native.create(state.app_id, state.token, state.channel_name, state.user_id, self())
rescue
_e in UndefinedFunctionError ->
reraise(
Expand Down Expand Up @@ -125,4 +125,22 @@ defmodule Membrane.Agora.Sink do
:ok = Native.write_audio_data(buffer.payload, state.native_state)
{[], state}
end

@impl true
def handle_info(:keyframe_request, %{playback: :playing} = ctx, state) do
video_pad =
ctx.pads
|> Map.keys()
|> Enum.find(fn
Pad.ref(:video, _id) -> true
_other_pad -> false
end)

{[event: {video_pad, %Membrane.KeyframeRequestEvent{}}], state}
end

@impl true
def handle_info(msg, _ctx, state) do
{[], state}
end
end
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ defmodule Membrane.Agora.Mixfile do
{:membrane_aac_format, "~> 0.8.0"},
{:membrane_raw_audio_format, "~> 0.12.0"},
{:unifex, "~> 1.1.0"},
{:membrane_file_plugin, "~> 0.16.0", only: :test},
{:membrane_file_plugin, "~> 0.17.2", only: :test},
{:membrane_h26x_plugin, "~> 0.10.0", only: :test},
{:membrane_aac_plugin, "~> 0.18.1", only: :test},
{:membrane_realtimer_plugin, "~> 0.9.0", only: :test},
Expand Down
7 changes: 4 additions & 3 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@
"finch": {:hex, :finch, "0.18.0", "944ac7d34d0bd2ac8998f79f7a811b21d87d911e77a786bc5810adb75632ada4", [: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", "69f5045b042e531e53edc2574f15e25e735b522c37e2ddb766e15b979e03aa65"},
"hpax": {:hex, :hpax, "0.2.0", "5a58219adcb75977b2edce5eb22051de9362f08236220c9e859a47111c194ff5", [:mix], [], "hexpm", "bea06558cdae85bed075e6c036993d43cd54d447f76d8190a8db0dc5893fa2f1"},
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
"logger_backends": {:hex, :logger_backends, "1.0.0", "09c4fad6202e08cb0fbd37f328282f16539aca380f512523ce9472b28edc6bdf", [:mix], [], "hexpm", "1faceb3e7ec3ef66a8f5746c5afd020e63996df6fd4eb8cdb789e5665ae6c9ce"},
"makeup": {:hex, :makeup, "1.1.2", "9ba8837913bdf757787e71c1581c21f9d2455f4dd04cfca785c70bbfff1a76a3", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cce1566b81fbcbd21eca8ffe808f33b221f9eee2cbc7a1706fc3da9ff18e6cac"},
"makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"},
"makeup_erlang": {:hex, :makeup_erlang, "1.0.0", "6f0eff9c9c489f26b69b61440bf1b238d95badae49adac77973cbacae87e3c2e", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "ea7a9307de9d1548d2a72d299058d1fd2339e3d398560a0e46c27dab4891e4d2"},
"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_core": {:hex, :membrane_core, "1.0.1", "08aa546c0d131c66f8b906b3dfb2b8f2749b56859f6fc52bd3ac846b944b3baa", [:mix], [{:bunch, "~> 1.6", [hex: :bunch, repo: "hexpm", optional: false]}, {:qex, "~> 0.3", [hex: :qex, repo: "hexpm", optional: false]}, {:ratio, "~> 3.0", [hex: :ratio, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a35ed68561bdf0a2dbb2f994333be78cf4e1c4d734e4cd927d77d92049bb1273"},
"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_core": {:hex, :membrane_core, "1.1.0", "c3bbaa5af7c26a7c3748e573efe343c2104801e3463b9e491a607e82860334a4", [:mix], [{:bunch, "~> 1.6", [hex: :bunch, repo: "hexpm", optional: false]}, {:qex, "~> 0.3", [hex: :qex, repo: "hexpm", optional: false]}, {:ratio, "~> 3.0 or ~> 4.0", [hex: :ratio, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3209d7f7e86d736cb7caffbba16b075c571cebb9439ab939ed6119c50fb59a5"},
"membrane_file_plugin": {:hex, :membrane_file_plugin, "0.17.2", "650e134c2345d946f930082fac8bac9f5aba785a7817d38a9a9da41ffc56fa92", [:mix], [{:logger_backends, "~> 1.0", [hex: :logger_backends, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}], "hexpm", "df50c6040004cd7b901cf057bd7e99c875bbbd6ae574efc93b2c753c96f43b9d"},
"membrane_h264_format": {:hex, :membrane_h264_format, "0.6.1", "44836cd9de0abe989b146df1e114507787efc0cf0da2368f17a10c47b4e0738c", [:mix], [], "hexpm", "4b79be56465a876d2eac2c3af99e115374bbdc03eb1dea4f696ee9a8033cd4b0"},
"membrane_h265_format": {:hex, :membrane_h265_format, "0.2.0", "1903c072cf7b0980c4d0c117ab61a2cd33e88782b696290de29570a7fab34819", [:mix], [], "hexpm", "6df418bdf242c0d9f7dbf2e5aea4c2d182e34ac9ad5a8b8cef2610c290002e83"},
"membrane_h26x_plugin": {:hex, :membrane_h26x_plugin, "0.10.2", "caf2790d8c107df35f8d456b45f4e09fb9c56ce6c7669a3a03f7d59972e6ed82", [: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]}, {:membrane_h265_format, "~> 0.2.0", [hex: :membrane_h265_format, repo: "hexpm", optional: false]}], "hexpm", "becf1ac4a589adecd850137ccd61a33058f686083a514a7e39fcd721bcf9fb2e"},
Expand All @@ -36,7 +37,7 @@
"nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"},
"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"},
"qex": {:hex, :qex, "0.5.1", "0d82c0f008551d24fffb99d97f8299afcb8ea9cf99582b770bd004ed5af63fd6", [:mix], [], "hexpm", "935a39fdaf2445834b95951456559e9dc2063d0a055742c558a99987b38d6bab"},
"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"},
"ratio": {:hex, :ratio, "4.0.1", "3044166f2fc6890aa53d3aef0c336f84b2bebb889dc57d5f95cc540daa1912f8", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:numbers, "~> 5.2.0", [hex: :numbers, repo: "hexpm", optional: false]}], "hexpm", "c60cbb3ccdff9ffa56e7d6d1654b5c70d9f90f4d753ab3a43a6bf40855b881ce"},
"req": {:hex, :req, "0.4.14", "103de133a076a31044e5458e0f850d5681eef23dfabf3ea34af63212e3b902e2", [:mix], [{:aws_signature, "~> 0.3.2", [hex: :aws_signature, repo: "hexpm", optional: true]}, {:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [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]}, {:nimble_ownership, "~> 0.2.0 or ~> 0.3.0", [hex: :nimble_ownership, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "2ddd3d33f9ab714ced8d3c15fd03db40c14dbf129003c4a3eb80fac2cc0b1b08"},
"shmex": {:hex, :shmex, "0.5.1", "81dd209093416bf6608e66882cb7e676089307448a1afd4fc906c1f7e5b94cf4", [:mix], [{:bunch_native, "~> 0.5.0", [hex: :bunch_native, repo: "hexpm", optional: false]}, {:bundlex, "~> 1.0", [hex: :bundlex, repo: "hexpm", optional: false]}], "hexpm", "c29f8286891252f64c4e1dac40b217d960f7d58def597c4e606ff8fbe71ceb80"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
Expand Down
Loading