/membrane_portaudio_plugin

Raw audio retriever and player based on PortAudio

Primary LanguageElixirApache License 2.0Apache-2.0

Membrane PortAudio plugin

Hex.pm API Docs CircleCI

The plugin that captures and plays sound using the multiplatform PortAudio library.

Installation

Add the following line to your deps in mix.exs. Run mix deps.get.

{:membrane_portaudio_plugin, "~> 0.19.3"}

This package depends on the PortAudio library. The precompiled build will be pulled and linked automatically. However, should there be any problems, consider installing it manually.

When running on linux ALSA (alsa-lib) needs to be present on the system for the precompiled build to work. In most cases it's installed by default, however in case it's not present you can install it manually.

Manual instalation of dependencies

Ubuntu

sudo apt-get install alsa
sudo apt-get install portaudio19-dev

Arch/Manjaro

pacman -S alsa-lib
pacman -S portaudio

MacOS

brew install portaudio

Tasks

The mix pa_devices task prints available audio devices and their IDs, which you can pass to the Membrane.PortAudio.Source or Membrane.PortAudio.Sink.

Sample usage

The pipeline below should play a raw file to a default output device.

defmodule Example.Pipeline do
  use Membrane.Pipeline

  alias Membrane.PortAudio

  @impl true
  def handle_init(_ctx, _opts) do
    structure = 
      child(:file_src, %Membrane.Element.File.Source{location: "file.raw"})
      |> child(:pa_sink, PortAudio.Sink)
    
    {[spec: structure], %{}}
  end
end

Membrane.Pipeline.start_link(Example.Pipeline)
Process.sleep(:infinity)

And this one should forward sound from the default input to the default output. DO NOT USE WITHOUT HEADPHONES to avoid audio feedback.

defmodule Example.Pipeline do
  use Membrane.Pipeline

  alias Membrane.PortAudio

  @impl true
  def handle_init(_ctx, _opts) do
    structure =
      child(:pa_src, PortAudio.Source)
      |> child(:pa_sink, PortAudio.Sink)

    {[spec: structure], %{}}
  end
end

Membrane.Pipeline.start_link(Example.Pipeline)
Process.sleep(:infinity)

Low latency

To reduce the latency of the sink and/or source, you can:

  • set the latency option to :low to configure the sound card in the low latency mode,
  • reduce the portaudio_buffer_size to make PortAudio produce/consume smaller audio chunks,

for example:

child(:pa_src, %PortAudio.Source{latency: :low, portaudio_buffer_size: 32})
|> child(:pa_sink, %PortAudio.Sink{latency: :low, portaudio_buffer_size: 32})

Testing

Tests contain some cases that use PortAudio stuff instead of mocking. Such cases require the presence of at least one input and output sound card, thus they are disabled by default. To enable them, run

mix test --include soundcard

Copyright and License

Copyright 2018, Software Mansion

Software Mansion

Licensed under the Apache License, Version 2.0