-
Notifications
You must be signed in to change notification settings - Fork 2
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
Support OPUS #24
Support OPUS #24
Changes from 34 commits
b490ec9
32692e7
117ba41
22be939
8171bc2
48561d8
2ef5e2f
9fbfb4c
b1c0359
40c00c8
ada11a6
ab46734
67b969b
60f8900
9a55bd9
a54e060
60c680b
c8ea493
60c3a37
4ece42a
2d5ac3f
c4dd318
8b8c77e
bd25ab8
4c1d370
ae9461c
373739f
3a228bd
d0d2896
6126357
94377d5
fd0a686
9faf7cf
300951f
eb8bb15
5e4f34d
4f9d08a
cd4b061
e7143bc
08024b8
df7ba2b
53cad24
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,7 +24,7 @@ UNIFEX_TERM create(UnifexEnv *env, char *appId, char *token, char *channelId, | |
scfg.enableVideo = true; | ||
scfg.useStringUid = false; | ||
if (state->service->initialize(scfg) != agora::ERR_OK) { | ||
AG_LOG(ERROR, "Failed to initialize service"); | ||
AG_LOG(ERROR, "Failed to initialize sink service"); | ||
unifex_release_state(env, state); | ||
return create_result_error(env, "Failed to initialize service"); | ||
} | ||
|
@@ -151,12 +151,18 @@ UNIFEX_TERM update_audio_stream_format(UnifexEnv *env, int sampleRate, | |
} | ||
|
||
UNIFEX_TERM write_audio_data(UnifexEnv *env, UnifexPayload *payload, | ||
SinkState *state) { | ||
CodecAudio codec, SinkState *state) { | ||
agora::rtc::EncodedAudioFrameInfo audioFrameInfo; | ||
audioFrameInfo.sampleRateHz = state->sampleRate; | ||
audioFrameInfo.numberOfChannels = state->numberOfChannels; | ||
audioFrameInfo.samplesPerChannel = state->samplesPerChannelPerFrame; | ||
audioFrameInfo.codec = agora::rtc::AUDIO_CODEC_TYPE::AUDIO_CODEC_AACLC; | ||
|
||
if (codec == CODEC_AUDIO_AAC) { | ||
audioFrameInfo.codec = agora::rtc::AUDIO_CODEC_TYPE::AUDIO_CODEC_AACLC; | ||
} else if (codec == CODEC_AUDIO_OPUS) { | ||
audioFrameInfo.codec = agora::rtc::AUDIO_CODEC_TYPE::AUDIO_CODEC_OPUS; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [NIT] I would warn if other codec was passed here. I know that now the only options for CodecAudio are |
||
|
||
if (state->audioEncodedFrameSender->sendEncodedAudioFrame( | ||
reinterpret_cast<uint8_t *>(payload->data), payload->size, | ||
audioFrameInfo) != true) { | ||
|
@@ -186,13 +192,13 @@ void handle_destroy_state(UnifexEnv *env, SinkState *state) { | |
AG_LOG(ERROR, "Failed to disconnect from Agora channel!"); | ||
return; | ||
} | ||
AG_LOG(INFO, "Disconnected from Agora channel successfully"); | ||
AG_LOG(INFO, "[Sink] Disconnected from Agora channel successfully"); | ||
state->connection = NULL; | ||
} | ||
|
||
if (state->service) { | ||
state->service->release(); | ||
AG_LOG(INFO, "Agora service released successfully"); | ||
AG_LOG(INFO, "[Sink] Agora service released successfully"); | ||
state->service = NULL; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ defmodule Membrane.Agora.Sink do | |
|
||
require Membrane.Pad, as: Pad | ||
|
||
alias Membrane.{AAC, Opus} | ||
alias Membrane.Agora.Sink.Native | ||
|
||
def_input_pad :video, | ||
|
@@ -16,8 +17,22 @@ defmodule Membrane.Agora.Sink do | |
|
||
def_input_pad :audio, | ||
availability: :on_request, | ||
accepted_format: Membrane.AAC, | ||
flow_control: :auto | ||
accepted_format: any_of(Membrane.AAC, Membrane.Opus), | ||
flow_control: :auto, | ||
options: [ | ||
sample_rate: [ | ||
spec: pos_integer(), | ||
default: 48_000, | ||
description: """ | ||
Sample rate of the audio stream going through :audio pad. | ||
|
||
Used only if the audio codec is `Membrane.Opus`. If the audio codec is | ||
`Membrane.AAC`, sample rate value will be passed in the stream format. | ||
|
||
Defaults to 48 000. | ||
""" | ||
] | ||
] | ||
|
||
def_options app_id: [ | ||
spec: String.t(), | ||
|
@@ -54,7 +69,8 @@ defmodule Membrane.Agora.Sink do | |
token: opts.token, | ||
channel_name: opts.channel_name, | ||
user_id: opts.user_id, | ||
native_state: nil | ||
native_state: nil, | ||
last_frame_duration: nil | ||
} | ||
|
||
{[], state} | ||
|
@@ -69,8 +85,8 @@ defmodule Membrane.Agora.Sink do | |
_e in UndefinedFunctionError -> | ||
reraise( | ||
""" | ||
Couldn't setup NIF. Perhaps you have forgotten to set LD_LIBRARY_PATH: | ||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:#{Path.expand("#{__ENV__.file}/../../../agora_sdk")} | ||
Couldn't setup NIF. Perhaps you have forgotten to set LD_LIBRARY_PATH: \ | ||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:#{Path.expand("#{__ENV__.file}/../../../agora_sdk")} \ | ||
""", | ||
__STACKTRACE__ | ||
) | ||
|
@@ -96,18 +112,24 @@ defmodule Membrane.Agora.Sink do | |
end | ||
|
||
@impl true | ||
def handle_stream_format(Pad.ref(:audio, _id), stream_format, _ctx, state) do | ||
def handle_stream_format(Pad.ref(:audio, _id), %Membrane.AAC{} = aac, _ctx, state) do | ||
{:ok, native_state} = | ||
Native.update_audio_stream_format( | ||
stream_format.sample_rate, | ||
stream_format.channels, | ||
stream_format.samples_per_frame, | ||
aac.sample_rate, | ||
aac.channels, | ||
aac.samples_per_frame, | ||
state.native_state | ||
) | ||
|
||
{[], %{state | native_state: native_state}} | ||
end | ||
|
||
@impl true | ||
def handle_stream_format(Pad.ref(:audio, _id), %Opus{}, _ctx, state) do | ||
# audio stream format will be updated in handle_buffer/4 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [NIT] this comment is quite ambiguos for me |
||
{[], state} | ||
end | ||
|
||
@impl true | ||
def handle_buffer(Pad.ref(:video, _id), buffer, _ctx, state) do | ||
:ok = | ||
|
@@ -121,8 +143,38 @@ defmodule Membrane.Agora.Sink do | |
end | ||
|
||
@impl true | ||
def handle_buffer(Pad.ref(:audio, _id), buffer, _ctx, state) do | ||
:ok = Native.write_audio_data(buffer.payload, state.native_state) | ||
def handle_buffer(Pad.ref(:audio, _id) = pad, buffer, ctx, state) do | ||
stream_format = | ||
case ctx.pads[pad].stream_format do | ||
%Opus{} -> :opus | ||
%AAC{} -> :aac | ||
end | ||
|
||
state = | ||
if stream_format == :opus and buffer.metadata.duration != state.last_frame_duration do | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
update_frame_duration(buffer.metadata.duration, pad, ctx, state) | ||
else | ||
state | ||
end | ||
|
||
:ok = Native.write_audio_data(buffer.payload, stream_format, state.native_state) | ||
{[], state} | ||
end | ||
|
||
defp update_frame_duration(frame_duration, pad, ctx, state) do | ||
pad_data = ctx.pads[pad] | ||
|
||
sample_rate = pad_data.options.sample_rate | ||
samples_per_frame = (frame_duration * sample_rate) |> div(1000) | ||
|
||
{:ok, native_state} = | ||
Native.update_audio_stream_format( | ||
sample_rate, | ||
pad_data.stream_format.channels, | ||
samples_per_frame, | ||
state.native_state | ||
) | ||
|
||
%{state | native_state: native_state, last_frame_duration: frame_duration} | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,14 @@ | ||
defmodule Membrane.Agora.Sink.Native do | ||
@moduledoc false | ||
|
||
if match?(%{os: "linux", architecture: "x86_64"}, Bundlex.get_target()) do | ||
target = Bundlex.get_target() | ||
|
||
if match?(%{os: "linux", architecture: "x86_64"}, target) do | ||
use Unifex.Loader | ||
else | ||
IO.warn(""" | ||
Agora SDK used by #{inspect(__MODULE__)} works only on linux with architecture x86_64, while \ | ||
you are now on #{inspect(target.os)} with architecture #{inspect(target.architecture)}. | ||
""") | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,14 @@ | ||
defmodule Membrane.Agora.Source.Native do | ||
@moduledoc false | ||
|
||
if match?(%{os: "linux", architecture: "x86_64"}, Bundlex.get_target()) do | ||
target = Bundlex.get_target() | ||
|
||
if match?(%{os: "linux", architecture: "x86_64"}, target) do | ||
use Unifex.Loader | ||
else | ||
IO.warn(""" | ||
Agora SDK used by #{inspect(__MODULE__)} works only on linux with architecture x86_64, while \ | ||
you are now on #{inspect(target.os)} with architecture #{inspect(target.architecture)}. | ||
""") | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.