Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b296f71
Add high-level client API with per-peer threading
devopvoid Oct 18, 2026
a3e4a00
Add client API guide and example
devopvoid Oct 18, 2026
4cc51d9
Release frames delivered to client frame handlers
devopvoid Oct 18, 2026
02c1713
Fix web example server for Jetty 12.1
devopvoid Oct 18, 2026
5ec6cac
Port the web example to the client API
devopvoid Oct 18, 2026
bd6c34d
Check decoding against the handler in the slow frame test
devopvoid Oct 19, 2026
f9aeab1
Bound complete ICE gathering by a timeout
devopvoid Oct 19, 2026
3bf42aa
Port the WHEP example to the client API
devopvoid Oct 19, 2026
62d4ac9
Start the get-started guide with the client API
devopvoid Oct 19, 2026
071a232
Send DTMF tones through client API senders
devopvoid Oct 19, 2026
1284e0a
Bound the messages a data channel keeps for its handler
devopvoid Oct 19, 2026
761bcb5
Make the offer collision tests collide every time
devopvoid Oct 19, 2026
ba5d501
Add VideoView, a Swing component for client API video
devopvoid Oct 19, 2026
a039024
Add WHIP and WHEP sessions to the client API
devopvoid Oct 19, 2026
a824cd9
Keep the JVM crash report of failed native test runs
devopvoid Oct 19, 2026
7c52018
Never dispose a runtime's factory under a closing peer
devopvoid Oct 19, 2026
e584e3c
Point the README to the client API
devopvoid Oct 19, 2026
1341eca
Put sources of the core API on client API tracks
devopvoid Oct 19, 2026
3d1ad06
Wait for whenClosed in the runtime close test
devopvoid Oct 19, 2026
95a719b
Report the last DTMF tone before the tones' future completes
devopvoid Oct 19, 2026
35fae9b
Test sending a media file through client API tracks
devopvoid Oct 19, 2026
f88d962
Switch cameras in a client API camera track
devopvoid Oct 19, 2026
2a3d4e2
Record client API senders and remote tracks
devopvoid Oct 19, 2026
a9b437c
List devices on machines without an audio system
devopvoid Oct 19, 2026
1da3b10
Accept the negotiated video codec in the client recorder test
devopvoid Oct 19, 2026
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
6 changes: 5 additions & 1 deletion .github/actions/test-natives/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ runs:
uses: actions/upload-artifact@v7
with:
name: test-reports-native-${{ inputs.platform-name }}
path: '**/target/surefire-reports/'
# A native crash ends the test JVM with a report of its own beside the
# module, which names the thread that crashed and what it ran.
path: |
**/target/surefire-reports/
**/hs_err_pid*.log
if-no-files-found: ignore
retention-days: 7
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ The library provides a comprehensive set of Java classes that map to the WebRTC
## Features

- **Complete WebRTC API implementation** - Includes peer connections, media devices, data channels, and more
- **Client API** - A high-level layer that negotiates by itself, keeps your code off WebRTC's threads, and closes everything with one call; with WHIP and WHEP sessions and a Swing video view
- **Cross-platform support** - Works on Windows, macOS, and Linux (x64, ARM, ARM64)
- **Media capabilities** - Audio and video capture from cameras and microphones
- **Desktop capture** - Screen and application window sharing
Expand All @@ -34,6 +35,7 @@ The library provides a comprehensive set of Java classes that map to the WebRTC
For more detailed information, check out the documentation:

- [Quickstart](https://jrtc.dev/guide/get-started) - Get up and running quickly with webrtc-java
- [Client API](https://jrtc.dev/guide/client-api) - Calls, media and data channels without the threading pitfalls
- [Guides](https://jrtc.dev/guide/) - Comprehensive documentation on using the library
- [Examples](https://jrtc.dev/guide/examples) - Sample code demonstrating various features
- [Media Files](https://jrtc.dev/guide/media/media-files) - Sending video and audio files with the media module
Expand Down
814 changes: 814 additions & 0 deletions design/client-api.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/.vitepress/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ function sidebarGuide(): DefaultTheme.SidebarItem[] {
items: [
{ text: 'What is webrtc-java?', link: '/introduction' },
{ text: 'Getting Started', link: '/get-started' },
{ text: 'Client API', link: '/client-api' },
],
},
{
Expand Down
631 changes: 631 additions & 0 deletions docs/guide/client-api.md

Large diffs are not rendered by default.

47 changes: 35 additions & 12 deletions docs/guide/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,26 @@

This section provides an overview of the example applications included in the `webrtc-examples` Maven module. These examples demonstrate various features and capabilities of the webrtc-java library.

## Client API

The [`ClientApiExample`](https://github.com/devopvoid/webrtc-java/blob/master/webrtc-examples/src/main/java/dev/onvoid/webrtc/examples/ClientApiExample.java) connects two peers in one process with the [Client API](/guide/client-api), and sends video, audio and chat messages from one to the other. It needs no audio or video hardware and no server.

**Key features demonstrated:**
- Creating a headless `WebRtc` runtime, which needs no microphone or speakers
- Connecting two peers through a signaling that carries JSON text, as a WebSocket would
- Letting perfect negotiation run the offer and answer exchange, with one polite peer
- Pushing video frames, and audio in pieces of any length
- Receiving remote tracks, their frames and their audio
- Exchanging messages on a data channel
- Reading the connection's statistics once a second
- Closing the peers, tracks and factory by closing the runtime

This example is the shortest way to see a complete call working, and a starting point for applications built on the client API.

```bash
mvn exec:java -D"exec.mainClass=dev.onvoid.webrtc.examples.ClientApiExample" -D"exec.args=10"
```

## PeerConnection

The [`PeerConnectionExample`](https://github.com/devopvoid/webrtc-java/blob/master/webrtc-examples/src/main/java/dev/onvoid/webrtc/examples/PeerConnectionExample.java) demonstrates how to set up a peer connection with audio and video tracks to be able to send and receive media.
Expand All @@ -17,15 +37,18 @@ This example provides a foundation for building WebRTC applications that need to

## WHEP

The [`WhepExample`](https://github.com/devopvoid/webrtc-java/blob/master/webrtc-examples/src/main/java/dev/onvoid/webrtc/examples/WhepExample.java) demonstrates an implementation of WebRTC HTTP Egress Protocol (WHEP) client, which is a standardized protocol for WebRTC ingestion.
The [`WhepExample`](https://github.com/devopvoid/webrtc-java/blob/master/webrtc-examples/src/main/java/dev/onvoid/webrtc/examples/WhepExample.java) implements a client of the WebRTC HTTP Egress Protocol (WHEP), which receives a stream from a server, with the [Client API](/guide/client-api).

**Key features demonstrated:**
- Setting up a WebRTC peer connection
- Creating and sending an SDP offer to a WHEP endpoint
- Receiving and processing an SDP answer
- Establishing media streaming over WebRTC
- Receiving a stream from a WHEP endpoint with `Whep`
- Logging the stream's video frames and audio
- Ending the session, which deletes it on the server

This example is useful for applications that need to receive media streams from WHEP-compatible servers, such as live streaming platforms. The endpoint and the number of seconds to receive are optional:

This example is useful for applications that need to receive media streams from WHEP-compatible servers, such as live streaming platforms.
```bash
mvn exec:java -D"exec.mainClass=dev.onvoid.webrtc.examples.WhepExample" -D"exec.args=http://localhost:8889/mystream/whep 10"
```

## Codec List

Expand Down Expand Up @@ -116,15 +139,15 @@ mvn exec:java -D"exec.mainClass=dev.onvoid.webrtc.examples.EncryptedRecordingExa

## Web Client

The [`WebClientExample`](https://github.com/devopvoid/webrtc-java/blob/master/webrtc-examples/src/main/java/dev/onvoid/webrtc/examples/web/WebClientExample.java) demonstrates how to combine WebSocket signaling with WebRTC peer connections for real-time communication between web and Java clients.
The [`WebClientExample`](https://github.com/devopvoid/webrtc-java/blob/master/webrtc-examples/src/main/java/dev/onvoid/webrtc/examples/web/WebClientExample.java) calls a browser from Java over WebSocket signaling, with the [Client API](/guide/client-api). The browser client is served by the example's `WebServer`.

**Key features demonstrated:**
- Connecting to a signaling server using WebSockets
- Setting up audio and video media tracks
- Creating and managing WebRTC peer connections
- Handling signaling messages (offers, answers, ICE candidates)
- Joining and leaving rooms for multi-user communication
- Using custom audio sources for audio streaming
- Implementing a `Signaling` over the application's own message format, which also names the sender and receiver of each message
- Sending generated audio and video, pushed into tracks of the runtime
- Letting the peer negotiate by itself, and starting a new peer whenever the browser joins the room
- Joining and leaving rooms
- Logging the audio and video the browser sends

This example is valuable for applications that need to establish WebRTC connections between Java clients and web browsers, enabling cross-platform real-time communication with audio and video.

Expand Down
103 changes: 92 additions & 11 deletions docs/guide/get-started.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Get Started

This guide will help you get started with webrtc-java quickly. We'll cover installation, basic setup, and simple examples to demonstrate core functionality.
This guide will help you get started with webrtc-java quickly. We'll cover installation, a first call with the client API, and the same steps with the core API.

## Supported Platforms
Maven Central artifacts contain native libraries that can be loaded on the following platforms:
Expand Down Expand Up @@ -114,7 +114,86 @@ implementation group: "dev.onvoid.webrtc", name: "webrtc-java", version: "{{ VER
implementation group: "dev.onvoid.webrtc", name: "webrtc-java", version: "{{ VERSION }}", classifier: "linux-aarch32"
```

## Basic Setup
## Your First Call

webrtc-java has two APIs. The [Client API](/guide/client-api) in `dev.onvoid.webrtc.client` negotiates by itself, keeps your code off WebRTC's threads, and closes everything it created with one call. The core API in `dev.onvoid.webrtc` mirrors WebRTC's own classes one to one, for full control. Start with the client API; [Using the Core API](#using-the-core-api) below shows the same steps with the core API.

### Create the Runtime

A `WebRtc` runtime owns everything the client API creates. Closing it, here at the end of the try-with-resources block, closes it all:

```java
import dev.onvoid.webrtc.client.*;

try (WebRtc rtc = WebRtc.create()) {
// Peers, tracks and channels go here.
}
```

`WebRtc.create()` captures the microphone and plays to the speakers. `WebRtc.builder().audio(AudioMode.HEADLESS).build()` needs no audio hardware at all, which suits servers and tests.

### Connect to a Peer

Two peers find each other through signaling: they exchange offers, answers and ICE candidates over a channel you provide, such as a WebSocket. The library has no transport of its own; you hand it a function that sends, and pass it what the other side sent:

```java
Peer peer = rtc.createPeer(PeerOptions.builder()
.iceServer("stun:stun.l.google.com:19302")
.polite(true)
.signaling(message -> socket.send(message.toJson()))
.build());

socket.onText(text -> peer.signal(SignalMessage.fromJson(text)));
```

The peer negotiates by itself whenever its tracks or channels change. When both sides send an offer at the same moment, the polite one gives way, so set `polite(true)` on exactly one of the two peers. The JSON messages are the ones browsers use, so the other side can be a web page.

### Send and Receive Media

```java
peer.addTrack(rtc.media().microphone());
peer.addTrack(rtc.media().camera());

peer.onTrack(track -> {
System.out.println("Receiving " + track.kind());

if (track.isVideo()) {
track.asVideo().onFrame(frame -> render(frame));
}
});

peer.onStateChange(state -> System.out.println("Call is " + state));
```

Handlers run on a thread of the peer's own, one at a time and in order. They may take their time and may call any method, so a slow handler never stalls WebRTC.

### Exchange Messages

```java
DataChannel chat = peer.createChannel("chat");

chat.onMessage(message -> System.out.println("Peer says: " + message.text()));
chat.send("Hello");
```

Messages sent before the channel opens are sent once it does.

### Hang Up

`peer.close()` ends the call; closing the runtime ends every call and releases the camera, the microphone and the native resources. Operations return `CompletableFuture`s, which a thread such as `main` may wait for:

```java
peer.whenConnected().get(10, TimeUnit.SECONDS);
// ...
peer.close();
```

The [Client API](/guide/client-api) guide covers everything else: pushing your own audio and video, manual negotiation for WHIP and WHEP, statistics and errors. The [`ClientApiExample`](https://github.com/devopvoid/webrtc-java/blob/master/webrtc-examples/src/main/java/dev/onvoid/webrtc/examples/ClientApiExample.java) runs a whole call between two peers in one process, without any hardware.

## Using the Core API

The core API leaves negotiation, threads and the lifetime of native objects to you. The steps below make the same call with it.


### Initialize the WebRTC Library

Expand Down Expand Up @@ -149,7 +228,7 @@ RTCPeerConnection peerConnection = factory.createPeerConnection(config, new Peer
});
```

## Signaling
### Signaling

WebRTC requires a signaling mechanism to exchange connection information between peers. The library doesn't provide this, so you'll need to implement it using your preferred method (WebSockets, HTTP, etc.).

Expand Down Expand Up @@ -215,7 +294,7 @@ signalingChannel.onIceCandidate(candidateMessage -> {
});
```

### Letting the Peer Connection Create the Description
#### Letting the Peer Connection Create the Description

`setLocalDescription` can also be called with only an observer. It then creates the offer or the answer, whichever the signaling state calls for, and applies it in one step, so nothing can change in between. That makes it the simpler way to implement "perfect negotiation". Read the result with `getLocalDescription()` once the observer reports success:

Expand All @@ -233,7 +312,7 @@ peerConnection.setLocalDescription(new SetSessionDescriptionObserver() {
});
```

### Adding Candidates and Knowing the Outcome
#### Adding Candidates and Knowing the Outcome

`addIceCandidate(candidate)` reports nothing and fails silently when the remote description is not set yet. The form that takes an `AddIceCandidateObserver` is queued behind any pending offer/answer operation, as the standard requires, so a candidate can be added right after `setRemoteDescription()` without waiting for it, and the observer says whether it was accepted:

Expand Down Expand Up @@ -263,9 +342,9 @@ public void onSelectedCandidatePairChanged(RTCCandidatePairChangeEvent event) {
}
```

## Media Streams
### Media Streams

### Accessing Media Devices
#### Accessing Media Devices

To query media devices (cameras and microphones):

Expand All @@ -287,7 +366,7 @@ for (AudioDevice device : audioDevices) {
}
```

### Creating Media Tracks
#### Creating Media Tracks

To create audio and video tracks:

Expand Down Expand Up @@ -317,7 +396,7 @@ AudioTrack audioTrack = factory.createAudioTrack("audio0", audioSource);
Audio devices can be specified via the `AudioDeviceModule`, see the guide on [Audio Devices][audio-devices] for more details.
:::

### Adding Tracks to Peer Connection
#### Adding Tracks to Peer Connection

```java
import java.util.ArrayList;
Expand All @@ -331,7 +410,7 @@ RTCRtpSender videoSender = peerConnection.addTrack(videoTrack, streamIds);
RTCRtpSender audioSender = peerConnection.addTrack(audioTrack, streamIds);
```

### Receiving Tracks
#### Receiving Tracks

A remote track arrives in `onTrack` with the transceiver that carries it. To learn when its media actually starts flowing, for example to show a video only once there is something to show, set an `RTCRtpReceiverObserver`; an `RTCRtpSenderObserver` does the same for the first packet a sender sends. Either is called right away when that has already happened:

Expand All @@ -353,7 +432,7 @@ public void onTrack(RTCRtpTransceiver transceiver) {

An observer belongs to the `RTCRtpReceiver` or `RTCRtpSender` object it was set through, and is removed when that object is disposed. `getId()` identifies a sender or receiver, and `RTCRtpSender.getStreams()` returns the stream IDs its track was added with.

## Cleanup
### Cleanup

Always properly dispose of resources when you're done:

Expand Down Expand Up @@ -381,13 +460,15 @@ factory.dispose();

Now that you have a basic understanding of webrtc-java, you can explore more advanced features:

- [Client API][client-api] - Everything the client API does, and how its threads work
- [Data Channels][data-channels] - Learn more about data channels
- [RTC Stats][rtc-stats] - Monitor connection quality
- [Desktop Capture][desktop-capture] - Share screens and windows
- [All Guides][overview] - Complete list of guides

For a complete API reference, check the [JavaDoc][javadoc].

[client-api]: /guide/client-api
[audio-devices]: /guide/audio/audio-devices
[data-channels]: /guide/data/data-channels
[rtc-stats]: /guide/monitoring/rtc-stats
Expand Down
2 changes: 2 additions & 0 deletions docs/guide/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ webrtc-java is a Java wrapper for the [WebRTC Native API](https://webrtc.github.

The library provides a comprehensive set of Java classes that map to the WebRTC C++ API, making it possible to establish peer-to-peer connections, transmit audio and video, share screens, and exchange arbitrary data between applications.

It has two APIs. The [Client API](/guide/client-api) negotiates connections by itself, keeps application code off WebRTC's threads, and releases everything it created with one call, which makes it the place to start. The core API maps WebRTC's classes one to one, for applications that need full control.

## Overview

For more detailed information, check out the documentation:
Expand Down
9 changes: 9 additions & 0 deletions docs/guide/media/media-recording.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ A sender's frames are recorded as they leave the encoder, a receiver's as they g
Keep the senders and receivers undisposed while recording. The recorder asks them for key frames, and a disposed one cannot be asked.
:::

With the [Client API](/guide/client-api), a recorder takes its senders and remote tracks directly:

```java
recorder.addTrack(videoSender); // a Sender from peer.addTrack
recorder.addTrack(remoteTrack); // a RemoteTrack from peer.onTrack
```

The peer keeps its native senders and receivers to itself and asks them for key frames on its own thread, so nothing needs to be kept undisposed: removing a sender or closing the peer ends the track in the recording, and `stop()` still finishes the file.

## Containers

The container follows the file name:
Expand Down
Loading
Loading