From bf31727522b5031ecce2a599d7948d60809e40db Mon Sep 17 00:00:00 2001 From: SendableMetatype <263203301+SendableMetatype@users.noreply.github.com> Date: Mon, 7 Sep 2026 18:08:32 +0200 Subject: [PATCH] fix: throw instead of aborting when the default audio device module fails to initialize When no AudioDeviceModule is passed, PeerConnectionFactory lets libwebrtc create the platform default, and libwebrtc aborts the whole process when that module fails to initialize, which happens on hosts without an audio system such as containers and virtual machines. The factory now creates the default module itself, the same way AudioDeviceModule does, so the failure surfaces as an exception that tells the application to pass a module created with AudioLayer.kDummyAudio instead. --- .../cpp/src/JNI_PeerConnectionFactory.cpp | 21 +++++++++++++++++++ .../webrtc/PeerConnectionFactoryTests.java | 14 +++++++++++++ 2 files changed, 35 insertions(+) diff --git a/webrtc-jni/src/main/cpp/src/JNI_PeerConnectionFactory.cpp b/webrtc-jni/src/main/cpp/src/JNI_PeerConnectionFactory.cpp index 63f15b0b..4e87abcd 100644 --- a/webrtc-jni/src/main/cpp/src/JNI_PeerConnectionFactory.cpp +++ b/webrtc-jni/src/main/cpp/src/JNI_PeerConnectionFactory.cpp @@ -28,7 +28,9 @@ #include "JavaRef.h" #include "JavaString.h" #include "JavaUtils.h" +#include "WebRTCContext.h" +#include "api/audio/create_audio_device_module.h" #include "api/create_peerconnection_factory.h" #include "api/audio_codecs/builtin_audio_decoder_factory.h" #include "api/audio_codecs/builtin_audio_encoder_factory.h" @@ -89,6 +91,25 @@ JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_PeerConnectionFactory_initialize webrtc::scoped_refptr apm(processing); webrtc::scoped_refptr adm(audioDevModule); + if (!adm) { + // Without a module, the factory would create the platform default itself + // and abort the process when it fails to initialize, which happens on + // hosts without an audio system. Create it here instead, the same way + // AudioDeviceModule does, so a failure becomes an exception that the + // application can handle, for example by passing a module created + // with AudioLayer.kDummyAudio. + jni::WebRTCContext * context = static_cast(javaContext); + + adm = webrtc::CreateAudioDeviceModule(context->webrtcEnv, webrtc::AudioDeviceModule::kPlatformDefaultAudio); + + if (!adm) { + throw jni::Exception("Create the default AudioDeviceModule failed"); + } + if (adm->Init() != 0) { + throw jni::Exception("Initialize the default AudioDeviceModule failed. On a host without an audio system, pass an AudioDeviceModule created with AudioLayer.kDummyAudio."); + } + } + auto factory = webrtc::CreatePeerConnectionFactory( networkThread.get(), workerThread.get(), diff --git a/webrtc/src/test/java/dev/onvoid/webrtc/PeerConnectionFactoryTests.java b/webrtc/src/test/java/dev/onvoid/webrtc/PeerConnectionFactoryTests.java index 53872b50..8f78711e 100644 --- a/webrtc/src/test/java/dev/onvoid/webrtc/PeerConnectionFactoryTests.java +++ b/webrtc/src/test/java/dev/onvoid/webrtc/PeerConnectionFactoryTests.java @@ -29,6 +29,20 @@ class PeerConnectionFactoryTests extends TestBase { + @Test + void createWithoutAudioDeviceModule() { + // Without a module the factory creates the platform default. On a host + // without an audio system that must fail with an exception, not abort + // the process. + try { + PeerConnectionFactory factory = new PeerConnectionFactory(); + factory.dispose(); + } + catch (Error e) { + assertTrue(e.getMessage().contains("AudioDeviceModule"), e.getMessage()); + } + } + @Test void createWithAudioDeviceModule() { AudioDeviceModule audioDevModule = new AudioDeviceModule(AudioLayer.kDummyAudio);