Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
efd63c0
build: teach the FFmpeg build to cross-compile for every target
devopvoid Sep 20, 2026
3c267a3
ci: build FFmpeg on every platform and cache it
devopvoid Sep 20, 2026
4399bb2
build: make the media module part of the normal build
devopvoid Sep 20, 2026
9a9bba6
fix: stop the media module depending on natives it builds itself
devopvoid Sep 21, 2026
ed41b13
fix: normalise the FFmpeg install path before CMake parses it
devopvoid Sep 21, 2026
cedce08
fix: give each target a toolchain the media module can actually build…
devopvoid Sep 21, 2026
7841ad0
fix: keep the examples resolvable when CI invokes goals directly
devopvoid Sep 21, 2026
7802c18
fix: let FFmpeg find the macOS SDK, and print config.log when it cannot
devopvoid Sep 21, 2026
38de029
build: build the Linux natives against the Chromium sysroot
devopvoid Sep 21, 2026
9e7f557
ci: run the media tests against the natives that were cross compiled
devopvoid Sep 21, 2026
fb82ac1
fix: give the arm Linux builds the libc++ settings their toolchains omit
devopvoid Sep 21, 2026
275158c
fix: run the native tests without packaging the webrtc module
devopvoid Sep 22, 2026
bceb24f
fix: apply the encoder's adaptation requests to custom video sources
devopvoid Sep 25, 2026
da1f331
feat: decode the video and audio AVI files commonly carry
devopvoid Sep 25, 2026
38ae9a3
fix: keep video fed when a container stores audio far ahead of it
devopvoid Sep 25, 2026
1567535
feat: add a media file player example
devopvoid Sep 25, 2026
5c25ca0
feat: give the media file player the platform's look and feel
devopvoid Sep 25, 2026
0071e25
test: judge starved video by its lateness, and report why adaptation …
devopvoid Sep 26, 2026
efe9f1d
fix: pass the stats timestamp to Java as the jlong its constructor takes
devopvoid Sep 26, 2026
9fe9797
build: ship the licenses of the bundled native code in the platform jars
devopvoid Sep 26, 2026
8aa3b67
refactor: move the media module's classes to dev.onvoid.webrtc.media.…
devopvoid Sep 26, 2026
04de304
fix: let a player be closed from its own listener
devopvoid Sep 26, 2026
741d7bb
fix: keep the sources a player feeds alive until it is closed
devopvoid Sep 26, 2026
bcd44e7
fix: report a player that fails to open its decoders
devopvoid Sep 26, 2026
727eda2
fix: follow a change of audio format in the middle of a stream
devopvoid Sep 26, 2026
794e112
fix: clean up the native libraries extracted on Windows
devopvoid Sep 26, 2026
f980dfa
fix: stop as paused when playback fails
devopvoid Sep 26, 2026
72e81c1
fix: play the last few milliseconds of resampled audio
devopvoid Sep 26, 2026
0583d8c
build: update FFmpeg to 8.1
devopvoid Sep 26, 2026
af9690f
fix: give CI one ffmpeg.version to read
devopvoid Sep 26, 2026
af7fcee
fix: name the FFmpeg build after its release, not the commit
devopvoid Sep 26, 2026
5075f7e
docs: advertise the media module
devopvoid Sep 26, 2026
ff5dc66
feat: play RTSP streams, with timeouts and interruptible reads
devopvoid Sep 26, 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
11 changes: 11 additions & 0 deletions .github/actions/build/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ runs:
key: webrtc-${{ env.WEBRTC_CACHE_BRANCH }}-${{ inputs.platform-name }}-${{ hashFiles('webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt') }}-${{ hashFiles('webrtc-jni/pom.xml') }}
restore-keys: webrtc-${{ env.WEBRTC_CACHE_BRANCH }}-${{ inputs.platform-name }}-${{ hashFiles('webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt') }}-

- name: Derive the FFmpeg version from the pom
run: echo "FFMPEG_VERSION=$(sed -n 's|.*<ffmpeg.version>\([^<]*\)</ffmpeg.version>.*|\1|p' webrtc-java-media/pom.xml)" >> "$GITHUB_ENV"
shell: bash

- name: Set up FFmpeg cache
uses: actions/cache@v4
with:
path: ~/ffmpeg
key: ffmpeg-${{ env.FFMPEG_VERSION }}-${{ inputs.platform-name }}-${{ hashFiles('webrtc-java-media/src/main/cpp/dependencies/ffmpeg/CMakeLists.txt') }}-${{ hashFiles('webrtc-java-media/pom.xml') }}
restore-keys: ffmpeg-${{ env.FFMPEG_VERSION }}-${{ inputs.platform-name }}-${{ hashFiles('webrtc-java-media/src/main/cpp/dependencies/ffmpeg/CMakeLists.txt') }}-

- name: Set up Maven cache
uses: actions/cache@v4
with:
Expand Down
3 changes: 2 additions & 1 deletion .github/actions/prepare-linux/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ runs:
- name: Install required packages
run: |
sudo apt update
sudo apt install -y binutils cmake git locales lsb-release ninja-build pipewire pipewire-pulse pkg-config python3 python3-setuptools rsync unzip wget xz-utils
# nasm is what FFmpeg assembles its x86 code with.
sudo apt install -y binutils cmake git locales lsb-release nasm ninja-build pipewire pipewire-pulse pkg-config python3 python3-setuptools rsync unzip wget xz-utils

# Chromium Clang to be used with the clang toolchain file
#curl -s https://raw.githubusercontent.com/chromium/chromium/main/tools/clang/scripts/update.py | python3 - --output-dir=/opt/clang
Expand Down
3 changes: 3 additions & 0 deletions .github/actions/prepare-macos/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ runs:
run: |
# Required on macos-14
brew install python-setuptools
# nasm is what FFmpeg assembles its x86 code with, which the Intel
# build needs even though the runner itself is Apple Silicon.
brew install nasm
shell: bash

- name: Select Xcode version
Expand Down
13 changes: 13 additions & 0 deletions .github/actions/prepare-windows/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,16 @@ runs:
run: |
choco install ninja
shell: powershell

- name: Install MSYS2 and the FFmpeg build tools
run: |
# FFmpeg's configure and makefiles are shell scripts, so building it
# needs a POSIX shell even with MSVC, and that shell has to carry make
# and nasm. Git for Windows' bash carries neither.
if (-not (Test-Path "C:\msys64\usr\bin\bash.exe")) {
choco install msys2 --no-progress -y
}
C:\msys64\usr\bin\bash.exe -lc "pacman -Sy --noconfirm && pacman -S --needed --noconfirm make nasm diffutils pkgconf"
# Where the media module's CMake looks for it.
"MSYS2_ROOT=C:\msys64" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
shell: powershell
11 changes: 11 additions & 0 deletions .github/actions/release/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,17 @@ runs:
key: webrtc-${{ env.WEBRTC_CACHE_BRANCH }}-${{ inputs.platform-name }}-${{ hashFiles('webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt') }}-${{ hashFiles('webrtc-jni/pom.xml') }}
restore-keys: webrtc-${{ env.WEBRTC_CACHE_BRANCH }}-${{ inputs.platform-name }}-${{ hashFiles('webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt') }}-

- name: Derive the FFmpeg version from the pom
run: echo "FFMPEG_VERSION=$(sed -n 's|.*<ffmpeg.version>\([^<]*\)</ffmpeg.version>.*|\1|p' webrtc-java-media/pom.xml)" >> "$GITHUB_ENV"
shell: bash

- name: Set up FFmpeg cache
uses: actions/cache@v4
with:
path: ~/ffmpeg
key: ffmpeg-${{ env.FFMPEG_VERSION }}-${{ inputs.platform-name }}-${{ hashFiles('webrtc-java-media/src/main/cpp/dependencies/ffmpeg/CMakeLists.txt') }}-${{ hashFiles('webrtc-java-media/pom.xml') }}
restore-keys: ffmpeg-${{ env.FFMPEG_VERSION }}-${{ inputs.platform-name }}-${{ hashFiles('webrtc-java-media/src/main/cpp/dependencies/ffmpeg/CMakeLists.txt') }}-

- name: Set up Maven cache
uses: actions/cache@v4
with:
Expand Down
41 changes: 39 additions & 2 deletions .github/actions/test-natives/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,50 @@ runs:
- name: Install the natives into the local repository
run: |
VERSION=$(sed -n '0,/<version>/s|.*<version>\([^<]*\)</version>.*|\1|p' pom.xml)
JAR=$(ls natives/webrtc-java-*.jar | head -n 1)
JAR=$(find natives -path '*webrtc-jni*' -name 'webrtc-java-*.jar' | head -n 1)
echo "Installing $JAR as webrtc-java:$VERSION:${{ inputs.classifier }}"
mvn -B -q install:install-file -Dfile="$JAR" -DgroupId=dev.onvoid.webrtc \
-DartifactId=webrtc-java -Dversion="$VERSION" -Dpackaging=jar \
-Dclassifier=${{ inputs.classifier }}
shell: bash

# Both native libraries go into the directory the media module's tests
# already read from, which is where its own build collects them. That is
# what puts them on the class path, and it is also what makes the reactor
# below work: webrtc-java's natives are a classifier artifact of a module
# that is in that reactor, and Maven answers a dependency on such a thing
# with the module's output directory, which holds no native library at
# all. Coming from a directory instead, they are simply found.
- name: Unpack the natives where the tests look for them
run: |
MEDIA_JAR=$(find natives -name 'webrtc-java-media-*-${{ inputs.classifier }}.jar' | head -n 1)
WEBRTC_JAR=$(find natives -path '*webrtc-jni*' -name 'webrtc-java-*.jar' | head -n 1)

if [ -z "$MEDIA_JAR" ]; then
echo "No webrtc-java-media natives for ${{ inputs.classifier }} in the artifact" >&2
exit 1
fi

MEDIA_JAR="$PWD/$MEDIA_JAR"
WEBRTC_JAR="$PWD/$WEBRTC_JAR"

mkdir -p webrtc-java-media/target/natives
cd webrtc-java-media/target/natives
# jar rather than unzip: the JDK is set up above, and unzip is not on
# every runner image.
"$JAVA_HOME/bin/jar" xf "$MEDIA_JAR"
"$JAVA_HOME/bin/jar" xf "$WEBRTC_JAR"
rm -rf META-INF
ls -l
shell: bash

# One reactor for both, so that webrtc-java-media resolves webrtc-java
# from it. Testing rather than installing: webrtc attaches the host
# natives from webrtc-jni/target during its package phase, and on a runner
# that only downloaded them there is no such directory.
#
# The native build is off: these natives were cross compiled by another
# job, and this runner is here to run them, not to build them again.
- name: Test
run: mvn -B -pl webrtc test -P${{ inputs.profile }}
run: mvn -B -pl webrtc,webrtc-java-media test -DskipNativeBuild -P${{ inputs.profile }}
shell: bash
17 changes: 15 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
# The media module builds FFmpeg from its third-party submodule.
submodules: true

- id: prepare
name: Prepare build
Expand All @@ -53,7 +56,9 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: natives-${{ matrix.platform.name }}
path: webrtc-jni/target/webrtc-java-*.jar
path: |
webrtc-jni/target/webrtc-java-*.jar
webrtc-java-media/target/webrtc-java-media-*.jar
if-no-files-found: error

build-linux:
Expand All @@ -72,6 +77,9 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
# The media module builds FFmpeg from its third-party submodule.
submodules: true

- id: prepare
name: Prepare build
Expand All @@ -91,7 +99,9 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: natives-${{ matrix.platform.name }}
path: webrtc-jni/target/webrtc-java-*.jar
path: |
webrtc-jni/target/webrtc-java-*.jar
webrtc-java-media/target/webrtc-java-media-*.jar
if-no-files-found: error

build-macos:
Expand All @@ -108,6 +118,9 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
# The media module builds FFmpeg from its third-party submodule.
submodules: true

- id: prepare-build
name: Prepare build
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ jobs:
uses: actions/checkout@v6
with:
fetch-tags: true
# The media module builds FFmpeg from its third-party submodule.
submodules: true

- name: Get tag from current branch
id: tag-selector
Expand Down Expand Up @@ -189,6 +191,8 @@ jobs:
uses: actions/checkout@v6
with:
fetch-tags: true
# The media module builds FFmpeg from its third-party submodule.
submodules: true

- name: Get tag from current branch
id: tag-selector
Expand Down Expand Up @@ -227,6 +231,8 @@ jobs:
uses: actions/checkout@v6
with:
fetch-tags: true
# The media module builds FFmpeg from its third-party submodule.
submodules: true

- name: Get tag from current branch
id: tag-selector
Expand Down
13 changes: 13 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,19 @@ EXTERNAL COMPONENTS
This product bundles WebRTC, which is available under a "3-clause BSD" license.
For details, see https://webrtc.github.io/webrtc-org/license.

WebRTC is linked statically into the webrtc-java platform jars, together with
the third-party code it builds in, among them libvpx, libyuv, OpenH264, libaom,
dav1d, Opus, BoringSSL, Abseil and, for H.264 decoding, Chromium's FFmpeg under
the GNU Lesser General Public License version 2.1 or later. Each platform jar
carries their licenses and WebRTC's patent grant under META-INF/licenses/webrtc.

The webrtc-java-media platform jars bundle FFmpeg (https://ffmpeg.org), which is
available under the GNU Lesser General Public License version 2.1 or later. It is
built from an unmodified FFmpeg release, without --enable-gpl and without
--enable-nonfree, and linked dynamically, so it can be replaced. Each platform
jar carries the license text and a notice naming the FFmpeg version and where
its source is, under META-INF/licenses/ffmpeg.

DOCUMENTATION

WebRTC 1.0: Real-time Communication Between Browsers
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ The library provides a comprehensive set of Java classes that map to the WebRTC
- **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
- **Media file playback** - Send video and audio files over a peer connection in place of a camera and microphone, with the optional FFmpeg-based `webrtc-java-media` module
- **Data channels** - Bidirectional peer-to-peer data exchange
- **Statistics API** - Detailed metrics for monitoring connection quality
- **Simple integration** - Available as a Maven dependency
Expand All @@ -28,6 +29,7 @@ For more detailed information, check out the documentation:
- [Quickstart](https://jrtc.dev/guide/get-started) - Get up and running quickly with webrtc-java
- [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
- [Build Notes](https://jrtc.dev/guide/build) - Instructions for building the library from source

## License
Expand Down
34 changes: 28 additions & 6 deletions docs/guide/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,22 +54,44 @@ This example is particularly useful for applications that need to implement scre

## Media File

The [`MediaFileExample`](https://github.com/devopvoid/webrtc-java/blob/master/webrtc-examples/src/media/java/dev/onvoid/webrtc/examples/MediaFileExample.java) demonstrates how to send a media file over a peer connection, in place of a camera and a microphone. See the [Media Files](/guide/media/media-files) guide for the API it uses.
The [`MediaFileExample`](https://github.com/devopvoid/webrtc-java/blob/master/webrtc-examples/src/main/java/dev/onvoid/webrtc/examples/MediaFileExample.java) demonstrates how to send a media file over a peer connection, in place of a camera and a microphone. See the [Media Files](/guide/media/media-files) guide for the API it uses.

**Key features demonstrated:**
- Opening a media file with a `MediaFileSource`
- Opening a media file, or a live RTSP stream, with a `MediaFileSource`
- Reading what the source contains from its `MediaInfo`
- Creating audio and video tracks from the media sources it feeds
- Adding those tracks to a peer connection
- Following playback through a `MediaPlayerListener`

This example is useful for applications that stream pre-recorded media, or that need a dependable stand-in for a camera in testing.
This example is useful for applications that stream pre-recorded media, relay an IP camera into WebRTC, or need a dependable stand-in for a camera in testing.

::: warning
This example needs the `webrtc-java-media` module, which is opt-in while it is being brought up on every platform, so it is built and run with the `with-media-extension` profile:
::: info
This example needs the `webrtc-java-media` module, which builds FFmpeg from the `third-party/ffmpeg` submodule. Make sure the submodule is checked out before building, as the [Media Files](/guide/media/media-files) guide describes.

```bash
mvn exec:java -D"exec.mainClass=dev.onvoid.webrtc.examples.MediaFileExample" -D"exec.args=movie.mp4"
mvn exec:java -D"exec.mainClass=dev.onvoid.webrtc.examples.MediaFileExample" -D"exec.args=rtsp://camera.local/stream1"
```
:::

## Media File Player

The [`MediaFilePlayerExample`](https://github.com/devopvoid/webrtc-java/blob/master/webrtc-examples/src/main/java/dev/onvoid/webrtc/examples/MediaFilePlayerExample.java) is a Swing application that sends a media file, or a live RTSP stream, from one peer connection to another in the same process, then shows the received video and plays the received audio in sync. Start and Stop buttons set up and tear down the whole session.

**Key features demonstrated:**
- Connecting two peer connections in one application, without a signaling server
- Using one factory with a dummy audio layer to send the file, and another with the platform audio layer to play what is received
- Keeping audio and video in sync by sending both tracks in the same media stream
- Raising the video sender's `maxBitrate` above WebRTC's default, so a high-resolution file is not held to a fraction of its size
- Rendering received video frames in a Swing component with `VideoBufferConverter`
- Showing the source's format, the playback position, and live receive metrics (codec, resolution, frame rate, bitrate, packet loss, jitter, audio level) read from `getStats()`
- Releasing senders, peer connections, tracks and the source in order on Stop

::: info
Like the [Media File](#media-file) example, this one needs the `webrtc-java-media` module. The source argument is optional; a file can also be chosen from the window, or a stream URL typed into it. A stream URL's credentials are never shown, and the Loop box is disabled while a live stream plays, since it has no length to start over from.

```bash
mvn -Pwith-media-extension exec:java -D"exec.mainClass=dev.onvoid.webrtc.examples.MediaFileExample" -D"exec.args=movie.mp4"
mvn exec:java -D"exec.mainClass=dev.onvoid.webrtc.examples.MediaFilePlayerExample" -D"exec.args=movie.mp4"
```
:::

Expand Down
1 change: 1 addition & 0 deletions docs/guide/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ This section provides detailed guides for various features of the webrtc-java li
- [Media Devices](/guide/media/media-devices) - Working with audio and video devices
- [Bitrate and Framerate Constraints](/guide/media/constraints) - Controlling media quality
- [Send-only and Receive-only](/guide/media/directionality) - Configure transceiver directions (send-only, receive-only or inactive)
- [Media Files](/guide/media/media-files) - Sending video and audio files instead of a camera and microphone

## Audio

Expand Down
Loading
Loading