Skip to content

Libnice-based Interactive Connectivity Establishment (ICE) protocol support for Elixir

License

Notifications You must be signed in to change notification settings

membraneframework/ex_libnice

Repository files navigation

ExLibnice

Hex.pm API Docs CircleCI

Libnice-based Interactive Connectivity Establishment (ICE) protocol support for Elixir.

It is a part of Membrane Multimedia Framework.

Installation

First, install libnice on your system:

macOS

brew install libnice

Ubuntu

sudo apt-get install libnice-dev

The package can be installed by adding ex_libnice to your list of dependencies in mix.exs:

def deps do
  [
    {:ex_libnice, "~> 0.8.0"}
  ]
end

Usage

Basically this library works similarly to libnice.

ExLibnice can work both as CNode and as NIF. By default CNode implementation is used however, user can change it by passing proper option while starting ExLibnice (see below) or by config.exs:

config :ex_libnice, impl: :NIF

User can also choose whether to resolve mDNS addresses or not:

config :ex_libnice, mdns: false

Example flow can look in the following way (this is not complete i.e. runnable example).

Listed functions must be invoked on both peers.

# Init ExLibnice
{:ok, pid} =
  ExLibnice.start_link(
    impl: NIF,
    parent: self(),
    stun_servers: [
      %{server_addr: {64, 233, 161, 127}, server_port: 19_302},
      %{server_addr: "stun1.l.google.com", server_port: 19_302}
    ],
    controlling_mode: true,
    port_range: 0..0
  )

# Add stream, get local credentials
{:ok, stream_id} = ExLibnice.add_stream(ice, 1, "audio")
{:ok, credentials} = ExLibnice.get_local_credentials(ice, stream_id)

# Send local credentials to the remote peer
:socket.send(peer_socket, credentials)
# Receive remote credentials and set them on ExLibnice
{:ok, credentials} = :socket.recv(peer_socket)
:ok = ExLibnice.set_remote_credentials(ice, peer_credentials, stream_id)

# Start gathering candidates
:ok = ExLibnice.gather_candidates(ice, stream_id)
# Now we should prepare for receiving messages in form of `{:new_candidate_full, candidate}`
# and send them to the remote peer. If module that runs ExLibnice is a GenServer we can use
# handle_info/2 callback
@impl true
def handle_info({:new_candidate_full, candidate}, {peer_socket: peer_socket} = state) do
  :socket.send(peer_socket, {:peer_new_candidate_full, candidate})
end
# Set received peer candidates.
:ok = ExLibnice.set_remote_candidate(ice, peer_candidate, stream_id, 1)

This will start connectivity checks. Receiving message {:component_state_ready, stream_id, component_id} indicates that the given component in the given stream is ready to send and receive messages.

For more complete examples please refer to membrane_ice_plugin where we use ex_libnice or our integration test.

Copyright and License

Copyright 2020, Software Mansion

Software Mansion

Licensed under the Apache License, Version 2.0