diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn index bfaebad8d8..be84a6158b 100644 --- a/sdk/android/BUILD.gn +++ b/sdk/android/BUILD.gn @@ -164,6 +164,8 @@ if (is_android) { "src/java/org/webrtc/JniCommon.java", "src/java/org/webrtc/JniHelper.java", "src/java/org/webrtc/RefCountDelegate.java", + "src/java/org/webrtc/RtcError.java", + "src/java/org/webrtc/RtcException.java", "src/java/org/webrtc/WebRtcClassLoader.java", ] @@ -765,7 +767,9 @@ if (current_os == "linux" || is_android) { deps = [ ":base_jni", ":generated_external_classes_jni", + ":generated_external_classes_jni", ":generated_peerconnection_jni", + ":generated_rtcerror_jni", ":logging_jni", ":native_api_jni", ":native_api_stacktrace", @@ -1389,6 +1393,12 @@ if (current_os == "linux" || is_android) { jni_generator_include = "//sdk/android/src/jni/jni_generator_helper.h" } + generate_jni("generated_rtcerror_jni") { + sources = [ "src/java/org/webrtc/RtcError.java" ] + namespace = "webrtc::jni" + jni_generator_include = "//sdk/android/src/jni/jni_generator_helper.h" + } + generate_jni("generated_peerconnection_jni") { sources = [ "api/org/webrtc/AddIceObserver.java", diff --git a/sdk/android/api/org/webrtc/RtpTransceiver.java b/sdk/android/api/org/webrtc/RtpTransceiver.java index d2ba733db0..89299cef59 100644 --- a/sdk/android/api/org/webrtc/RtpTransceiver.java +++ b/sdk/android/api/org/webrtc/RtpTransceiver.java @@ -215,9 +215,9 @@ public class RtpTransceiver { nativeStopInternal(nativeRtpTransceiver); } - public void setCodecPreferences(List codecs) { + public RtcError setCodecPreferences(List codecs) { checkRtpTransceiverExists(); - nativeSetCodecPreferences(nativeRtpTransceiver, codecs); + return nativeSetCodecPreferences(nativeRtpTransceiver, codecs); } /** @@ -268,6 +268,6 @@ public class RtpTransceiver { private static native void nativeStopStandard(long rtpTransceiver); private static native boolean nativeSetDirection( long rtpTransceiver, RtpTransceiverDirection rtpTransceiverDirection); - private static native void nativeSetCodecPreferences( + private static native RtcError nativeSetCodecPreferences( long rtpTransceiver, List codecs); } diff --git a/sdk/android/instrumentationtests/src/org/webrtc/RtpCapabilitiesTest.java b/sdk/android/instrumentationtests/src/org/webrtc/RtpCapabilitiesTest.java index 961ecd5c70..e04b2361dd 100644 --- a/sdk/android/instrumentationtests/src/org/webrtc/RtpCapabilitiesTest.java +++ b/sdk/android/instrumentationtests/src/org/webrtc/RtpCapabilitiesTest.java @@ -158,7 +158,8 @@ public class RtpCapabilitiesTest { assertNotNull(targetCodec); - transceiver.setCodecPreferences(Arrays.asList(targetCodec)); + RtcError result = transceiver.setCodecPreferences(Arrays.asList(targetCodec)); + assertTrue(result.isSuccess()); SdpObserverLatch sdpLatch = new SdpObserverLatch(); pc.createOffer(sdpLatch, new MediaConstraints()); @@ -183,6 +184,18 @@ public class RtpCapabilitiesTest { String expected = "a=rtpmap:" + targetPayload + " " + targetCodec.name + "/" + targetCodec.getClockRate(); assertEquals(expected, rtpMap); + + // Set an invalid codec preference and check that an error is returned. + RtpCapabilities audioCapabilities = + factory.getRtpSenderCapabilities(MediaStreamTrack.MediaType.MEDIA_TYPE_AUDIO); + assertNotNull(audioCapabilities); + RtpCapabilities.CodecCapability audioCodec = audioCapabilities.getCodecs().get(0); + + result = transceiver.setCodecPreferences(Arrays.asList(audioCodec)); + assertTrue(result.isError()); + Throwable resultException = result.error(); + assertTrue(resultException instanceof RtcException); + assertTrue(resultException.getMessage().startsWith("Invalid codec preferences:")); } private List getMediaDescriptions(String[] sdpDescriptionLines) { diff --git a/sdk/android/src/java/org/webrtc/RtcError.java b/sdk/android/src/java/org/webrtc/RtcError.java new file mode 100644 index 0000000000..854541c82f --- /dev/null +++ b/sdk/android/src/java/org/webrtc/RtcError.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +package org.webrtc; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +/** + * RtcError class is used to handle errors obtainable from WebRTC operations. + */ +public class RtcError { + private final RtcException error; + + private RtcError(RtcException error) { + this.error = error; + } + + /** Creates a RtcError with success */ + @CalledByNative + public static RtcError success() { + return new RtcError(null); + } + + /** Creates a RtcError with an error */ + @CalledByNative + public static RtcError error(@NonNull String error) { + return new RtcError(new RtcException(error)); + } + + public boolean isSuccess() { + return error == null; + } + + public boolean isError() { + return error != null; + } + + /** + * Retrieve the error from the WebRTC operation. + * If the operation was successful, this will return null. + */ + @Nullable + public RtcException error() { + return error; + } + + /** Throws the error if it is not null. */ + public void throwError() { + if (error != null) { + throw error; + } + } +} diff --git a/sdk/android/src/java/org/webrtc/RtcException.java b/sdk/android/src/java/org/webrtc/RtcException.java new file mode 100644 index 0000000000..d2dafbae2d --- /dev/null +++ b/sdk/android/src/java/org/webrtc/RtcException.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +package org.webrtc; + +/** + * RtcException represents exceptions that are specific to the WebRTC library. Refer to the file + * api/rtc_error.h for more information. + */ +public class RtcException extends RuntimeException { + + public RtcException(String message) { + super(message); + } +} diff --git a/sdk/android/src/jni/pc/rtp_transceiver.cc b/sdk/android/src/jni/pc/rtp_transceiver.cc index 748dbb7f10..4d5b00d79d 100644 --- a/sdk/android/src/jni/pc/rtp_transceiver.cc +++ b/sdk/android/src/jni/pc/rtp_transceiver.cc @@ -13,6 +13,7 @@ #include #include "sdk/android/generated_peerconnection_jni/RtpTransceiver_jni.h" +#include "sdk/android/generated_rtcerror_jni/RtcError_jni.h" #include "sdk/android/native_api/jni/java_types.h" #include "sdk/android/src/jni/jni_helpers.h" #include "sdk/android/src/jni/pc/media_stream_track.h" @@ -140,15 +141,22 @@ ScopedJavaLocalRef JNI_RtpTransceiver_CurrentDirection( : nullptr; } -void JNI_RtpTransceiver_SetCodecPreferences( +ScopedJavaLocalRef JNI_RtpTransceiver_SetCodecPreferences( JNIEnv* jni, jlong j_rtp_transceiver_pointer, const JavaParamRef& j_codecs) { - std::vector codecs = - JavaListToNativeVector( - jni, j_codecs, &JavaToNativeRtpCodecCapability); - reinterpret_cast(j_rtp_transceiver_pointer) - ->SetCodecPreferences(codecs); + std::vector codecs; + if (j_codecs) { + codecs = JavaListToNativeVector( + jni, j_codecs, &JavaToNativeRtpCodecCapability); + } + RTCError error = + reinterpret_cast(j_rtp_transceiver_pointer) + ->SetCodecPreferences(codecs); + if (!error.ok()) { + return Java_RtcError_error(jni, NativeToJavaString(jni, error.message())); + } + return Java_RtcError_success(jni); } void JNI_RtpTransceiver_StopInternal(JNIEnv* jni,