Library / SDK
libnice/libnice avatar
libnice/libnice

libnice: a C implementation of ICE for peer to peer connectivity

An implementation of the IETF’s Interactive Connectivity Establishment (ICE) standard — this is an official read-only mirror of the upstream repository at https://gitlab.freedesktop.org/libnice/libnice/. File issues there and create pull requests there too instead of here.

649 stars221 forksCNOASSERTION

At a glance

What is it?
libnice is the GLib implementation of the IETF Interactive Connectivity Establishment standard, written in C and built with Meson, with STUN, a socket abstraction and optional GStreamer elements. It is the connectivity layer under WebRTC style peer to peer media, and the GitHub copy is a read-only mirror of the upstream GitLab repository.
Who is it for?
Adopt libnice when you are writing C or GLib code that needs to negotiate peer to peer connectivity across NAT, and you are prepared to deal with a library whose upstream lives on GitLab. Do not adopt it for a browser based media stack, since a browser already ships its own ICE implementation, and do not expect to file issues here, because the project states that the GitHub repository is a read-only mirror.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 51 days ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A read-only mirror is not where you file your bug

The first thing to establish about this repository is that it is not the project. The description says it is an official read-only mirror of the upstream repository at https://gitlab.freedesktop.org/libnice/libnice/, and it asks you to file issues and create pull requests there instead of here.

That single fact shapes how you adopt the library. Any workflow that opens pull requests against the GitHub copy will go nowhere, and any automation that treats this repository as the source of truth will drift from what is actually shipped.

The project itself is the GLib ICE library. Nice implements the IETF Interactive Connectivity Establishment standard, which is the part of a peer to peer system that works out which network path two hosts can use to talk to each other when both are behind NAT, firewalls or both. The library is written in C, and the copyright notice in the README covers Collabora Ltd from 2006 to 2020 and Nokia Corporation from 2006 to 2011, which dates the work to the era when WebRTC was still being standardised.

The homepage is libnice.freedesktop.org. The licence is unusual in a useful way: SPDX-License-Identifier LGPL-2.1-or-later OR MPL-1.1, a dual licence where you pick either. The README points to the file COPYING, and the repository root carries COPYING, COPYING.LGPL and COPYING.MPL alongside an AUTHORS file.

For an engineer picking this up, the practical consequence of the dual licence is straightforward: LGPL means dynamic linking keeps the library out of your licensing obligations, and MPL means file level changes stay under MPL if you modify the library itself. Your own organisation's policy decides which route matters.

The directory layout maps directly onto the protocol

The README gives a short structural map of the tree, and it is more informative than it first appears because each directory corresponds to a layer of the problem.

The agent directory holds the ICE agent, which is the state machine that drives the whole negotiation. The stun directory holds the STUN implementation, which is the transport that carries the connectivity checks. The socket directory is the socket abstraction layer, which is what lets the agent work across platforms and let other components such as GStreamer plug in their own transports. The random directory handles random number generation, which matters for ICE because the foundation attribute used to distinguish candidates is randomised.

The nice directory is the library itself. The gst directory holds Gstreamer elements, which is the bridge that lets GStreamer pipelines use the library for connectivity. The docs directory holds design and API documentation, and the tests directory holds unit tests.

Two things the layout tells you that a feature list would not. First, STUN is a separate implementation rather than a dependency, so the library carries its own protocol code and you are not inheriting someone else's STUN parsing. Second, there is a socket abstraction layer rather than direct socket calls, which is the extension point for a platform that needs a different transport.

The root also carries a NEWS file, a TODO file and a .gitlab-ci.yml, which places the continuous integration on the GitLab side along with the source.

Building with Meson and running the test suite

The build uses the Meson build system, and the README gives the commands for Linux and Mac as the usual sequence. The build directory is created first, then compiled, then tested, then installed:

bash
  meson builddir
  ninja -C builddir
  ninja -C builddir test (or "meson test -C builddir" for more control)
  sudo ninja -C builddir install

The test step is worth noticing because it is part of the documented sequence rather than an afterthought, and the alternative form is mentioned in parentheses: ninja -C builddir test, or meson test -C builddir for more control. The repository ships a .lcovrc, so coverage configuration is present alongside the unit tests in the tests directory.

The dependency list in the README is short and tells you the shape of the library. glib at 2.56 or later is required, along with pkg-config. For the transport security side you need gnutls at 3.6.0 or later, or OpenSSL. Two further dependencies are marked optional: gupnp-igd at 0.2.5 or later, and gstreamer-1.14.

The optional gupnp-igd dependency is the interesting one. IGD stands for Internet Gateway Device, and this library links against an IGD daemon to discover and control a UPnP capable router on the local network. It is the mechanism by which a peer can ask the router to open a port mapping so an inbound candidate can work. It is optional because not every network has one and not every deployment wants to talk to the router.

The GStreamer requirement being optional tells you that the gst elements are a separate concern from the core library, so you can use the ICE agent without pulling in the multimedia stack.

The standards list is where the compatibility boundaries live

The README lists the standards relevant to the current implementation, and reading that list is the fastest way to understand what a peer to peer library built on it will and will not negotiate.

For ICE there are two references, RFC 8445 for the current standard and RFC 5245 marked as old. For STUN there are RFC 5389 and RFC 3489 marked as old. STUN Consent Freshness is RFC 7675, which is the mechanism that keeps a NAT mapping alive over time. TURN is RFC 5766, the relay protocol used when a direct path cannot be established.

Beyond the core four, the list continues to RTP in RFC 3550, ICE-TCP in RFC 6544, Trickle ICE at draft-ietf-ice-trickle-21, and XMPP Jingle ICE transport at XEP-0176.

That last one is worth pausing on, because it explains a large part of why this library exists. Jingle is the XMPP signalling extension for media, and it needs ICE to negotiate the media path. An XMPP client library that wants to establish a call needs an ICE implementation, and libnice is the one that ships with GLib and GStreamer, which is the stack most Linux desktops are built on.

Trickle ICE matters for latency, since it lets candidate pairs be exchanged while gathering is still running instead of waiting for the full candidate list. The draft status in the list suggests this area was still moving.

The README is also explicit about the future. Port Control Protocol, RFC 6887, and its obsolete predecessor NAT-PMP, RFC 6886, are listed as standards nice may additionally support in future. Nothing in that list is implemented today.

Where libnice stops and its neighbours begin

ICE is one layer of a stack, and the surrounding layers are where the practical limits of this library appear.

ICE negotiates a path. It does not carry your media. That is the job of the data transport, and the README's reference to RTP in RFC 3550 shows where the boundary sits: libnice tells you which address pair works, and something else moves the packets. In a GStreamer based pipeline the library supplies the connectivity and the pipeline's own elements handle the media.

It is also not a signalling implementation. ICE needs both peers to exchange their candidates, and that exchange travels over whatever signalling channel your application already has. XEP-0176 appears in the standards list because Jingle defines such a channel for XMPP, but libnice does not ship a full XMPP stack or a SDP negotiator for WebRTC style sessions on its own.

The distinction between direct and relayed paths is where behaviour differs most in the field. A direct candidate pair is what libnice aims to find. When that fails, TURN is the fallback, and TURN implies a relay server that you have to run, secure and maintain. The library implements the client side of that protocol, but the relay itself is a separate operational component.

A browser is the other neighbour. A modern browser already contains an ICE implementation, wired to the browser's own connectivity APIs. Using libnice in that situation duplicates a component the platform already provides, so it only makes sense outside the browser, in a native application or a server side component.

The examples directory shows three different shapes of usage

The repository ships four files under examples, one of which is the build definition and three of which are programs.

simple-example.c is the minimal case. threaded-example.c shows the same idea with threading, which is what you need when the application has other work to do while a connectivity check is in flight. sdp-example.c is the one to look at first if you are building anything resembling a session negotiation, since the name points at SDP, the session description format that carries media and connection information.

The naming of the first two is itself instructive. A connectivity library spends most of its time waiting, on STUN checks, on consent freshness refreshes, and on the trickle ICE timers. Treating it as synchronous gets you an application that stalls, and the threaded example exists to show the alternative.

The examples are built through examples/meson.build, which means they are part of the normal build rather than something you have to wire up by hand. That matters in practice, because example code that is not compiled tends to rot, and the one thing a developer evaluating a library like this will want is a program they can build and read.

Note what the examples directory does not contain. There is no example of a full WebRTC style session, no example of TURN relay configuration, and no example that sets up a browser compatible signalling flow. The library expects you to bring those pieces.

Maintenance, versioning and how to track upstream

There are no GitHub releases for this repository, so version tracking happens upstream and on the freedesktop GitLab. The last push to the mirror was on 2026-09-01, which tells you when the mirror was refreshed rather than when the library changed.

The versioning context sits in the subprojects directory and the meson.build and meson_options.txt files. The presence of a subprojects directory is the Meson mechanism for vendoring dependencies that are not installed system wide, which is a common source of build friction with a project like this when it needs a specific version of a dependency.

There is also a TODO file at the root, and the README's own statement that the project may in future support PCP and NAT-PMP gives a second hint about direction.

For the licence question, the dual LGPL-2.1-or-later OR MPL-1.1 statement means you choose. There is nothing here that requires legal advice, but there is a real difference in obligations between the two, and the choice is yours to make and to document.

For a team adopting this, the operational advice is short. Track the GitLab repository for changes, mirror from there rather than from GitHub, and if you vendor the library, vendor from the upstream tag rather than from the mirror, so that your provenance matches what upstream publishes.

Editorial conclusion

Adopt libnice when you are writing C or GLib code that needs to negotiate peer to peer connectivity across NAT, and you are prepared to deal with a library whose upstream lives on GitLab. Do not adopt it for a browser based media stack, since a browser already ships its own ICE implementation, and do not expect to file issues here, because the project states that the GitHub repository is a read-only mirror. Before you build, confirm your glib is at least 2.56 and that you have GnuTLS 3.6.0 or OpenSSL available, and decide early whether you need the optional gupnp-igd and gstreamer-1.14 dependencies.

Frequently asked questions

Where do I file issues and pull requests for libnice?

The GitHub repository is an official read-only mirror, so issues and pull requests belong at the upstream GitLab repository at https://gitlab.freedesktop.org/libnice/libnice/. The README asks you to create them there instead.

What dependencies does libnice need to build?

glib at 2.56 or later, pkg-config, and gnutls at 3.6.0 or later or OpenSSL. The gupnp-igd package at 0.2.5 or later and gstreamer-1.14 are optional.

How do you build and test libnice?

The build uses Meson. Run meson builddir, then ninja -C builddir, then ninja -C builddir test or meson test -C builddir for more control, and finish with sudo ninja -C builddir install.

What licence is libnice released under?

A dual licence, SPDX-License-Identifier LGPL-2.1-or-later OR MPL-1.1, with the full terms in the COPYING, COPYING.LGPL and COPYING.MPL files in the repository root.

Which parts of libnice are optional?

The gupnp-igd dependency for UPnP router control and gstreamer-1.14 for the GStreamer elements in the gst directory are both marked optional, so the core ICE agent can be used without them.

Official sources

  1. Issues
  2. libnice/libnice on GitHub
  3. Project website
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/libnice-libnice.svg)](https://hysenlabs.com/projects/libnice-libnice)