enzoqtvf
enzoqtvf
SMSoftware Mansion
Created by enzoqtvf on 1/10/2025 in #membrane-help
How to split a Raw Audio Buffer with 2 channels within frame into two different buffer
Actually I managed to achieve it thanks to chatGPT 😄 I created an element that will split RawAudio payload, and it was easy because a stereo frame alternates between the left and right channel and the binary data is structured as L1,R1,L2,R2..., Ln,Rn
3 replies
SMSoftware Mansion
Created by enzoqtvf on 6/20/2023 in #membrane-help
How to pass some client side parameters to an RTMP pipeline
I made a PR: https://github.com/membraneframework/membrane_rtmp_plugin/pull/57 it might not be the best way to do it, but it solved my issue in my case 🙂
4 replies
SMSoftware Mansion
Created by enzoqtvf on 6/20/2023 in #membrane-help
How to pass some client side parameters to an RTMP pipeline
Wondering if modifying the message_handler inside the RTMP plugin library like this would make sense:
defp do_handle_client_message(%Messages.Connect{app: app} = connect, _header, state) do
chunk_size = state.message_parser.chunk_size

[
%Messages.WindowAcknowledgement{size: @windows_acknowledgment_size},
%Messages.SetPeerBandwidth{size: @peer_bandwidth_size},
# stream begin type
%Messages.UserControl{event_type: 0x00, data: <<0, 0, 0, 0>>},
# by default the ffmpeg server uses 128 chunk size
%Messages.SetChunkSize{chunk_size: chunk_size}
]
|> Enum.each(&send_rtmp_payload(&1, state.socket, chunk_size))

{[tx_id], message_parser} = MessageParser.generate_tx_ids(state.message_parser, 1)

tx_id
|> Responses.connection_success()
|> send_rtmp_payload(state.socket, chunk_size, chunk_stream_id: 3)

Responses.on_bw_done()
|> send_rtmp_payload(state.socket, chunk_size, chunk_stream_id: 3)

{:cont,
%{
state
| message_parser: message_parser,
actions: state.actions ++ [{:notify_parent, {:rtmp_app, app}}]
}}
end
defp do_handle_client_message(%Messages.Connect{app: app} = connect, _header, state) do
chunk_size = state.message_parser.chunk_size

[
%Messages.WindowAcknowledgement{size: @windows_acknowledgment_size},
%Messages.SetPeerBandwidth{size: @peer_bandwidth_size},
# stream begin type
%Messages.UserControl{event_type: 0x00, data: <<0, 0, 0, 0>>},
# by default the ffmpeg server uses 128 chunk size
%Messages.SetChunkSize{chunk_size: chunk_size}
]
|> Enum.each(&send_rtmp_payload(&1, state.socket, chunk_size))

{[tx_id], message_parser} = MessageParser.generate_tx_ids(state.message_parser, 1)

tx_id
|> Responses.connection_success()
|> send_rtmp_payload(state.socket, chunk_size, chunk_stream_id: 3)

Responses.on_bw_done()
|> send_rtmp_payload(state.socket, chunk_size, chunk_stream_id: 3)

{:cont,
%{
state
| message_parser: message_parser,
actions: state.actions ++ [{:notify_parent, {:rtmp_app, app}}]
}}
end
That way I can get this information from my pipeline (note the addition of the actions)
4 replies
SMSoftware Mansion
Created by enzoqtvf on 6/20/2023 in #membrane-help
How to pass some client side parameters to an RTMP pipeline
Actually if that can help people so far I found I can see these informations in the rtmp connect message like this:
%Membrane.RTMP.Messages.Connect{
app: "call_control_id=enzoteststs&test=22",
type: "nonprivate",
supports_go_away: false,
flash_version: "FMLE/3.0 (compatible; Lavf59.27.100)",
swf_url: "rtmp://localhost:5002/call_control_id=enzoteststs&test=22",
tc_url: "rtmp://localhost:5002/call_control_id=enzoteststs&test=22",
tx_id: 1.0
}
%Membrane.RTMP.Messages.Connect{
app: "call_control_id=enzoteststs&test=22",
type: "nonprivate",
supports_go_away: false,
flash_version: "FMLE/3.0 (compatible; Lavf59.27.100)",
swf_url: "rtmp://localhost:5002/call_control_id=enzoteststs&test=22",
tc_url: "rtmp://localhost:5002/call_control_id=enzoteststs&test=22",
tx_id: 1.0
}
4 replies
SMSoftware Mansion
Created by enzoqtvf on 5/9/2023 in #membrane-help
Pipeline with RTMP source and AAC decoder
Hey, I tried and it does work 🙂
10 replies
SMSoftware Mansion
Created by enzoqtvf on 5/9/2023 in #membrane-help
Pipeline with RTMP source and AAC decoder
Ah I see interesting, now it makes more sense thanks !
10 replies
SMSoftware Mansion
Created by enzoqtvf on 5/9/2023 in #membrane-help
Pipeline with RTMP source and AAC decoder
I think I found my issue, I got it working by not using the Membrane.RTMP.SourceBin, but instead use Membrane.RTMP.Source, doing it that way:
def handle_init(_ctx, socket: socket) do
structure = [
child(:source, %Membrane.RTMP.Source{
socket: socket,
validator: Membrane.RTMP.DefaultMessageValidator
})
|> child(:demuxer, Membrane.FLV.Demuxer)
|> via_out(Pad.ref(:audio, 0))
|> child(:audio_parser, %Membrane.AAC.Parser{in_encapsulation: :none})
|> child(:decoder, Membrane.AAC.FDK.Decoder)
|> child(:converter, %Converter{
output_stream_format: %RawAudio{
sample_format: :f32le,
sample_rate: 16000,
channels: 1
}
})
|> child(:fake_sink, Membrane.Fake.Sink.Buffers)
]

{[spec: structure, playback: :playing], %{}}}
end
def handle_init(_ctx, socket: socket) do
structure = [
child(:source, %Membrane.RTMP.Source{
socket: socket,
validator: Membrane.RTMP.DefaultMessageValidator
})
|> child(:demuxer, Membrane.FLV.Demuxer)
|> via_out(Pad.ref(:audio, 0))
|> child(:audio_parser, %Membrane.AAC.Parser{in_encapsulation: :none})
|> child(:decoder, Membrane.AAC.FDK.Decoder)
|> child(:converter, %Converter{
output_stream_format: %RawAudio{
sample_format: :f32le,
sample_rate: 16000,
channels: 1
}
})
|> child(:fake_sink, Membrane.Fake.Sink.Buffers)
]

{[spec: structure, playback: :playing], %{}}}
end
Somehow the extra part: |> bin_output(:audio), that is part of the SourceBin was causing issues. Not sure exactly why, still a noob with Membrane 😄
10 replies
SMSoftware Mansion
Created by enzoqtvf on 5/9/2023 in #membrane-help
Pipeline with RTMP source and AAC decoder
Got the same result with this:
def handle_init(_ctx, socket: socket) do
structure = [
child(:source, %Membrane.RTMP.SourceBin{
socket: socket,
validator: Membrane.RTMP.DefaultMessageValidator
})
|> via_out(:audio)
|> child(:decoder, Membrane.AAC.FDK.Decoder)
|> child(:converter, %Converter{
output_stream_format: %RawAudio{
sample_format: :f32le,
sample_rate: 16000,
channels: 1
}
})
|> child(:sink, %Membrane.File.Sink{location: "test.pcm"})
]

{[spec: structure, playback: :playing], %{}}}
end
def handle_init(_ctx, socket: socket) do
structure = [
child(:source, %Membrane.RTMP.SourceBin{
socket: socket,
validator: Membrane.RTMP.DefaultMessageValidator
})
|> via_out(:audio)
|> child(:decoder, Membrane.AAC.FDK.Decoder)
|> child(:converter, %Converter{
output_stream_format: %RawAudio{
sample_format: :f32le,
sample_rate: 16000,
channels: 1
}
})
|> child(:sink, %Membrane.File.Sink{location: "test.pcm"})
]

{[spec: structure, playback: :playing], %{}}}
end
10 replies