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

Livebooks from membrane guide #268

Merged
merged 9 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.DS_Store
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,20 @@ In the subdirectories of this repository you can find some examples of using the
- [rtp_to_hls](https://github.com/membraneframework/membrane_demo/tree/master/rtp_to_hls) - receiving RTP stream and broadcasting it via HLS
- [rtsp_to_hls](https://github.com/membraneframework/membrane_demo/tree/master/rtsp_to_hls) - receiving RTSP stream and converting it to HLS
- [video_mixer](https://github.com/membraneframework/membrane_demo/tree/master/video_mixer) - how to mix audio and video files
- [speech_to_text](https://github.com/membraneframework/membrane_demo/tree/master/speech_to_text) - real-time speech recognition using [Whisper](https://github.com/openai/whisper) in [Livebook]
- [webrtc_to_hls](https://github.com/jellyfish-dev/membrane_rtc_engine/tree/master/examples/webrtc_to_hls) - converting WebRTC stream into HLS
- [webrtc_videoroom](https://github.com/jellyfish-dev/membrane_rtc_engine/tree/master/examples/webrtc_videoroom) - basic example of [Membrane RTC Engine](https://github.com/jellyfish-dev/membrane_rtc_engine.git). It's as simple as possible just to show you how to use our API.
-

Also there are some livebook examples located in [livebooks](https://github.com/membraneframework/membrane_demo/tree/master/livebooks) directory:

- [speech_to_text](https://github.com/membraneframework/membrane_demo/tree/master/livebooks/speech_to_text) - real-time speech recognition using [Whisper](https://github.com/openai/whisper) in [Livebook]
- [audio_mixer](https://github.com/membraneframework/membrane_demo/tree/master/livebooks/audio_mixer) - mix a beep sound into background music
- [messages_source_and_sink](https://github.com/membraneframework/membrane_demo/tree/master/livebooks/messages_source_and_sink) - setup a simple pipeline and send messages through it
- [playing_mp3_file](https://github.com/membraneframework/membrane_demo/tree/master/livebooks/playing_mp3_file) - read mp3 file, transcode to acc and play
- [rtmp](https://github.com/membraneframework/membrane_demo/tree/master/livebooks/rtmp) - send and receive `RTMP` stream
- [soundwave](https://github.com/membraneframework/membrane_demo/tree/master/livebooks/soundwave) - plot live audio amplitude on a graph
## Copyright and License

Copyright 2018, [Software Mansion](https://swmansion.com/?utm_source=git&utm_medium=readme&utm_campaign=membrane)
Copyright 2024, [Software Mansion](https://swmansion.com/?utm_source=git&utm_medium=readme&utm_campaign=membrane)

[![Software Mansion](https://logo.swmansion.com/logo?color=white&variant=desktop&width=200&tag=membrane-github)](https://swmansion.com/?utm_source=git&utm_medium=readme&utm_campaign=membrane)

Expand Down
10 changes: 10 additions & 0 deletions livebooks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Livebook examples

This folder contains interactive livebook examples. To launch them you need to install livebook first.

## Installation

It is recommended to install Livebook via command line ([see official installation guide](https://github.com/livebook-dev/livebook#escript)).

If livebook was installed directly from the official page, one should add `$PATH` variable to the Livebook environment:
![Setting path](./assets/path_set.png "Title")
Binary file added livebooks/assets/path_set.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions livebooks/audio_mixer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Membrane audio mixer

This livebook shows how to mix a beep sound into background music over a period of time.

To run the demo, [install Livebook](https://github.com/livebook-dev/livebook#escript) and open the `audio_mixer.livemd` file there.

## Copyright and License

Copyright 2024, [Software Mansion](https://swmansion.com/?utm_source=git&utm_medium=readme&utm_campaign=membrane)

[![Software Mansion](https://docs.membrane.stream/static/logo/swm_logo_readme.png)](https://swmansion.com/?utm_source=git&utm_medium=readme&utm_campaign=membrane)

Licensed under the [Apache License, Version 2.0](LICENSE)
Binary file added livebooks/audio_mixer/assets/beep.aac
Binary file not shown.
Binary file not shown.
120 changes: 120 additions & 0 deletions livebooks/audio_mixer/audio_mixer.livemd
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Mixing audio files

```elixir
File.cd(__DIR__)
Logger.configure(level: :error)

Mix.install([
{:membrane_core, "~> 1.0"},
{:membrane_audio_mix_plugin, "~> 0.16.0"},
{:membrane_file_plugin, "~> 0.16.0"},
{:membrane_mp3_mad_plugin, "~> 0.18.0"},
{:membrane_ffmpeg_swresample_plugin, "~> 0.19.0"},
{:membrane_aac_fdk_plugin, "~> 0.18.0"},
{:membrane_kino_plugin, github: "membraneframework-labs/membrane_kino_plugin", tag: "v0.3.1"},
{:membrane_tee_plugin, "~> 0.12.0"}
])
```

## Installation

To run this demo one needs to install native dependencies:

1. [MP3 MAD](https://github.com/membraneframework/membrane_mp3_mad_plugin/tree/v0.14.0#installation)
2. [AAC FDK](https://github.com/membraneframework/membrane_aac_fdk_plugin#installation)
3. [SWResample FFmpeg](https://github.com/membraneframework/membrane_ffmpeg_swresample_plugin#installation)

## Description

This is an example of mixing multiple short "beep" sound into background music, one by one, every second.

## Pipeline definition

Define all constants.

```elixir
n_beeps = 30
beep_filepath = "./assets/beep.aac"
background_filepath = "./assets/sample_music_short.mp3"
:ok
```

The file's "beep" sound input is decoded from `AAC` and split into separate inputs using the `Tee` element. These inputs are then filled into the mixer with corresponding time offsets.

```elixir
import Membrane.ChildrenSpec

alias Membrane.{File, AAC, Tee, Time}

beep_audio_input =
child({:file_source, :beep}, %File.Source{location: beep_filepath})
|> child({:decoder_aac, :beep}, AAC.FDK.Decoder)
|> child(:beeps, Tee.PushOutput)

beeps_split =
for i <- 1..n_beeps do
get_child(:beeps)
|> via_in(:input, options: [offset: Time.seconds(i)])
|> get_child(:mixer)
end

:ok
```

The background music is loaded from a file and then decoded from the `MP3` format to the appropriate `Raw Audio` format.

All mixer inputs must be of the same format.

```elixir
import Membrane.ChildrenSpec

alias Membrane.{File, RawAudio, MP3}
alias Membrane.FFmpeg.SWResample.Converter

background_audio_input =
child(:file_source, %File.Source{location: background_filepath})
|> child(:decoder_mp3, MP3.MAD.Decoder)
|> child(:converter, %Converter{
input_stream_format: %RawAudio{channels: 2, sample_format: :s24le, sample_rate: 44_100},
output_stream_format: %RawAudio{channels: 1, sample_format: :s16le, sample_rate: 44_100}
})
|> get_child(:mixer)

:ok
```

Mixer is created and directly connected to audio input of the player.

```elixir
import Membrane.ChildrenSpec

alias Membrane.{AudioMixer, AAC, Kino}

kino = Membrane.Kino.Player.new(audio: true)

mixer_output =
child(:mixer, Membrane.AudioMixer)
|> child(:encoder_aac, AAC.FDK.Encoder)
|> via_in(:audio)
|> child(:player, %Kino.Player.Sink{kino: kino})

:ok
```

Whole pipeline structure.

```elixir
spec = beeps_split ++ [beep_audio_input, background_audio_input, mixer_output]
:ok
```

## Playing audio

```elixir
alias Membrane.RCPipeline, as: RC

pipeline = RC.start!()
RC.exec_actions(pipeline, spec: spec)

kino
```
13 changes: 13 additions & 0 deletions livebooks/messages_source_and_sink/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Membrane messages source and sink

This livebook shows how to setup a simple pipeline and send messages through it.

To run the demo, [install Livebook](https://github.com/livebook-dev/livebook#escript) and open the `messages_source_and_sink.livemd` file there.

## Copyright and License

Copyright 2024, [Software Mansion](https://swmansion.com/?utm_source=git&utm_medium=readme&utm_campaign=membrane)

[![Software Mansion](https://docs.membrane.stream/static/logo/swm_logo_readme.png)](https://swmansion.com/?utm_source=git&utm_medium=readme&utm_campaign=membrane)

Licensed under the [Apache License, Version 2.0](LICENSE)
140 changes: 140 additions & 0 deletions livebooks/messages_source_and_sink/messages_source_and_sink.livemd
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# Messages source and sink

```elixir
File.cd(__DIR__)
Logger.configure(level: :error)

Mix.install([
{:membrane_core, "~> 1.0"}
])
```

## Erlang messages driven source

```elixir
defmodule MessageSource do
use Membrane.Source

require Membrane.Logger

def_output_pad :output,
flow_control: :push,
accepted_format: _any

def_options register_name: [
description: "The name under which the element's process will be registered",
spec: atom()
]


@impl true
def handle_init(_ctx, opts) do
Process.register(self(), opts.register_name)
{[], %{buffered: []}}
end

@impl true
def handle_playing(_ctx, state) do
{actions, state} = send_buffers(state)
{[stream_format: {:output, %Membrane.RemoteStream{type: :bytestream}}] ++ actions, state}
end

@impl true
def handle_info({:message, message}, ctx, state) do
state = %{state | buffered: state.buffered ++ [message]}

if ctx.playback == :playing do
send_buffers(state)
else
{[], state}
end
end

@impl true
def handle_info(msg, _ctx, state) do
Membrane.Logger.warning("Unknown message received: #{inspect(msg)}")
{[], state}
end

defp send_buffers(state) do
actions =
Enum.map(state.buffered, fn message ->
{:buffer, {:output, %Membrane.Buffer{payload: message}}}
end)

{actions, %{state | buffered: []}}
end
end
```

## Erlang messages driven sink

```elixir
defmodule MessageSink do
use Membrane.Sink

def_input_pad :input,
flow_control: :push,
accepted_format: _any

def_options receiver: [
description: "PID of the process that will receive messages from the sink",
spec: pid()
]

@impl true
def handle_init(_ctx, opts) do
{[], %{receiver: opts.receiver}}
end

@impl true
def handle_buffer(:input, buffer, _ctx, state) do
send(state.receiver, {:message, self(), buffer.payload})
{[], state}
end
end
```

## Pipeline definition and startup

```elixir
alias Membrane.RCPipeline
import Membrane.ChildrenSpec

defmodule MyPipeline do
use Membrane.Pipeline

@impl true
def handle_init(_ctx, opts) do
spec =
child(:source, %MessageSource{register_name: :messages_source})
|> child(:sink, %MessageSink{receiver: Keyword.get(opts, :receiver)})

{[spec: spec], nil}
end
end

{:ok, _supervisor, pipeline} = Membrane.Pipeline.start(MyPipeline, receiver: self())
payloads = 1..10

Task.async(fn ->
Enum.each(
payloads,
&send(:messages_source, {:message, &1})
)
end)

:ok
```

## Printing of the messages received and pipeline termination

```elixir
for _i <- 1..10 do
receive do
{:message, _pid, _value} = msg -> IO.inspect(msg)
end
end

RCPipeline.terminate(pipeline)
```
13 changes: 13 additions & 0 deletions livebooks/playing_mp3_file/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Membrane playing mp3 file demo

This livebook shows how to load `MP3` audio from the file, transcode it to the `AAC` codec, and play it.

To run the demo, [install Livebook](https://github.com/livebook-dev/livebook#escript) and open the `playing_mp3_file.livemd` file there.

## Copyright and License

Copyright 2024, [Software Mansion](https://swmansion.com/?utm_source=git&utm_medium=readme&utm_campaign=membrane)

[![Software Mansion](https://docs.membrane.stream/static/logo/swm_logo_readme.png)](https://swmansion.com/?utm_source=git&utm_medium=readme&utm_campaign=membrane)

Licensed under the [Apache License, Version 2.0](LICENSE)
Binary file added livebooks/playing_mp3_file/assets/sample.mp3
Binary file not shown.
Loading
Loading