Expose setCodecPreferences/getCapabilities for android

Bug: webrtc:15177
Change-Id: If61ef9a87bc4f68d73cef6e681461682ca48f034
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/304880
Reviewed-by: Sergey Silkin <ssilkin@webrtc.org>
Commit-Queue: Sergey Silkin <ssilkin@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40071}
This commit is contained in:
David Liu 2023-05-15 11:33:38 +00:00 committed by WebRTC LUCI CQ
parent 54519aa378
commit 784c339f34
11 changed files with 563 additions and 1 deletions

View File

@ -154,6 +154,7 @@ HyperConnect Inc. <*@hpcnt.com>
Intel Corporation <*@intel.com>
LG Electronics, Inc. <*@lge.com>
Life On Air Inc. <*@lifeonair.com>
LiveKit <*@livekit.io>
Meta Platforms, Inc. <*@meta.com>
Microsoft Corporation <*@microsoft.com>
MIPS Technologies <*@mips.com>

View File

@ -287,6 +287,7 @@ if (is_android) {
"api/org/webrtc/RTCStatsCollectorCallback.java",
"api/org/webrtc/RTCStatsReport.java",
"api/org/webrtc/RtcCertificatePem.java",
"api/org/webrtc/RtpCapabilities.java",
"api/org/webrtc/RtpParameters.java",
"api/org/webrtc/RtpReceiver.java",
"api/org/webrtc/RtpSender.java",
@ -734,6 +735,8 @@ if (current_os == "linux" || is_android) {
"src/jni/pc/rtc_certificate.h",
"src/jni/pc/rtc_stats_collector_callback_wrapper.cc",
"src/jni/pc/rtc_stats_collector_callback_wrapper.h",
"src/jni/pc/rtp_capabilities.cc",
"src/jni/pc/rtp_capabilities.h",
"src/jni/pc/rtp_parameters.cc",
"src/jni/pc/rtp_parameters.h",
"src/jni/pc/rtp_receiver.cc",
@ -1391,6 +1394,7 @@ if (current_os == "linux" || is_android) {
"api/org/webrtc/RTCStatsCollectorCallback.java",
"api/org/webrtc/RTCStatsReport.java",
"api/org/webrtc/RtcCertificatePem.java",
"api/org/webrtc/RtpCapabilities.java",
"api/org/webrtc/RtpParameters.java",
"api/org/webrtc/RtpReceiver.java",
"api/org/webrtc/RtpSender.java",
@ -1486,6 +1490,7 @@ if (is_android) {
"instrumentationtests/src/org/webrtc/PeerConnectionTest.java",
"instrumentationtests/src/org/webrtc/RendererCommonTest.java",
"instrumentationtests/src/org/webrtc/RtcCertificatePemTest.java",
"instrumentationtests/src/org/webrtc/RtpCapabilitiesTest.java",
"instrumentationtests/src/org/webrtc/RtpSenderTest.java",
"instrumentationtests/src/org/webrtc/RtpTransceiverTest.java",
"instrumentationtests/src/org/webrtc/SoftwareVideoDecoderFactoryTest.java",

View File

@ -15,7 +15,9 @@ import android.os.Process;
import androidx.annotation.Nullable;
import java.util.List;
import org.webrtc.Logging.Severity;
import org.webrtc.MediaStreamTrack;
import org.webrtc.PeerConnection;
import org.webrtc.RtpCapabilities;
import org.webrtc.audio.AudioDeviceModule;
import org.webrtc.audio.JavaAudioDeviceModule;
@ -471,6 +473,16 @@ public class PeerConnectionFactory {
return new AudioTrack(nativeCreateAudioTrack(nativeFactory, id, source.getNativeAudioSource()));
}
public RtpCapabilities getRtpReceiverCapabilities(MediaStreamTrack.MediaType mediaType) {
checkPeerConnectionFactoryExists();
return nativeGetRtpReceiverCapabilities(nativeFactory, mediaType);
}
public RtpCapabilities getRtpSenderCapabilities(MediaStreamTrack.MediaType mediaType) {
checkPeerConnectionFactoryExists();
return nativeGetRtpSenderCapabilities(nativeFactory, mediaType);
}
// Starts recording an AEC dump. Ownership of the file is transfered to the
// native code. If an AEC dump is already in progress, it will be stopped and
// a new one will start using the provided file.
@ -615,4 +627,8 @@ public class PeerConnectionFactory {
private static native void nativeInjectLoggable(JNILogging jniLogging, int severity);
private static native void nativeDeleteLoggable();
private static native void nativePrintStackTrace(int tid);
private static native RtpCapabilities nativeGetRtpSenderCapabilities(
long factory, MediaStreamTrack.MediaType mediaType);
private static native RtpCapabilities nativeGetRtpReceiverCapabilities(
long factory, MediaStreamTrack.MediaType mediaType);
}

View File

@ -0,0 +1,125 @@
/*
* Copyright 2023 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.Nullable;
import java.util.List;
import java.util.Map;
import org.webrtc.MediaStreamTrack;
public class RtpCapabilities {
public static class CodecCapability {
public int preferredPayloadType;
// Name used to identify the codec. Equivalent to MIME subtype.
public String name;
// The media type of this codec. Equivalent to MIME top-level type.
public MediaStreamTrack.MediaType kind;
// Clock rate in Hertz.
public Integer clockRate;
// The number of audio channels used. Set to null for video codecs.
public Integer numChannels;
// The "format specific parameters" field from the "a=fmtp" line in the SDP
public Map<String, String> parameters;
// The MIME type of the codec. This is a convenience field.
public String mimeType;
public CodecCapability() {}
@CalledByNative("CodecCapability")
CodecCapability(int preferredPayloadType, String name, MediaStreamTrack.MediaType kind,
Integer clockRate, Integer numChannels, String mimeType, Map<String, String> parameters) {
this.preferredPayloadType = preferredPayloadType;
this.name = name;
this.kind = kind;
this.clockRate = clockRate;
this.numChannels = numChannels;
this.parameters = parameters;
this.mimeType = mimeType;
}
@CalledByNative("CodecCapability")
int getPreferredPayloadType() {
return preferredPayloadType;
}
@CalledByNative("CodecCapability")
String getName() {
return name;
}
@CalledByNative("CodecCapability")
MediaStreamTrack.MediaType getKind() {
return kind;
}
@CalledByNative("CodecCapability")
Integer getClockRate() {
return clockRate;
}
@CalledByNative("CodecCapability")
Integer getNumChannels() {
return numChannels;
}
@CalledByNative("CodecCapability")
Map getParameters() {
return parameters;
}
}
public static class HeaderExtensionCapability {
private final String uri;
private final int preferredId;
private final boolean preferredEncrypted;
@CalledByNative("HeaderExtensionCapability")
HeaderExtensionCapability(String uri, int preferredId, boolean preferredEncrypted) {
this.uri = uri;
this.preferredId = preferredId;
this.preferredEncrypted = preferredEncrypted;
}
@CalledByNative("HeaderExtensionCapability")
public String getUri() {
return uri;
}
@CalledByNative("HeaderExtensionCapability")
public int getPreferredId() {
return preferredId;
}
@CalledByNative("HeaderExtensionCapability")
public boolean getPreferredEncrypted() {
return preferredEncrypted;
}
}
public List<CodecCapability> codecs;
public List<HeaderExtensionCapability> headerExtensions;
@CalledByNative
RtpCapabilities(List<CodecCapability> codecs, List<HeaderExtensionCapability> headerExtensions) {
this.headerExtensions = headerExtensions;
this.codecs = codecs;
}
@CalledByNative
public List<HeaderExtensionCapability> getHeaderExtensions() {
return headerExtensions;
}
@CalledByNative
List<CodecCapability> getCodecs() {
return codecs;
}
}

View File

@ -215,6 +215,11 @@ public class RtpTransceiver {
nativeStopInternal(nativeRtpTransceiver);
}
public void setCodecPreferences(List<RtpCapabilities.CodecCapability> codecs) {
checkRtpTransceiverExists();
nativeSetCodecPreferences(nativeRtpTransceiver, codecs);
}
/**
* The StopInternal method stops the RtpTransceiver, like Stop, but goes
* immediately to Stopped state.
@ -263,4 +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(
long rtpTransceiver, List<RtpCapabilities.CodecCapability> codecs);
}

View File

@ -582,7 +582,7 @@ public class PeerConnectionEndToEndTest {
}
}
private static class SdpObserverLatch implements SdpObserver {
static class SdpObserverLatch implements SdpObserver {
private boolean success;
private @Nullable SessionDescription sdp;
private @Nullable String error;

View File

@ -0,0 +1,217 @@
/*
* Copyright 2023 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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import androidx.annotation.Nullable;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.junit.Before;
import org.junit.Test;
import org.webrtc.PeerConnectionEndToEndTest.SdpObserverLatch;
import org.webrtc.RtpParameters.Encoding;
import org.webrtc.RtpTransceiver.RtpTransceiverInit;
/**
* Unit-tests for {@link RtpCapabilities}.
*/
public class RtpCapabilitiesTest {
private PeerConnectionFactory factory;
private PeerConnection pc;
static class CustomHardwareVideoEncoderFactory implements VideoEncoderFactory {
private final List<VideoCodecInfo> supportedCodecs;
public CustomHardwareVideoEncoderFactory(List<VideoCodecInfo> supportedCodecs) {
this.supportedCodecs = supportedCodecs;
}
@Override
public @Nullable VideoEncoder createEncoder(VideoCodecInfo info) {
return null;
}
@Override
public VideoCodecInfo[] getSupportedCodecs() {
return supportedCodecs.toArray(new VideoCodecInfo[0]);
}
}
static class CustomHardwareVideoDecoderFactory implements VideoDecoderFactory {
private final List<VideoCodecInfo> supportedCodecs;
public CustomHardwareVideoDecoderFactory(List<VideoCodecInfo> supportedCodecs) {
this.supportedCodecs = supportedCodecs;
}
@Nullable
@Override
public VideoDecoder createDecoder(VideoCodecInfo videoCodecInfo) {
return null;
}
@Override
public VideoCodecInfo[] getSupportedCodecs() {
return supportedCodecs.toArray(new VideoCodecInfo[0]);
}
}
@Before
public void setUp() {
PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions
.builder(InstrumentationRegistry.getTargetContext())
.setNativeLibraryName(TestConstants.NATIVE_LIBRARY)
.createInitializationOptions());
VideoCodecInfo vp8Codec = new VideoCodecInfo("VP8", new HashMap<>());
VideoCodecInfo h264Codec = new VideoCodecInfo("H264", new HashMap<>());
List<VideoCodecInfo> supportedCodecs = new ArrayList<>();
supportedCodecs.add(vp8Codec);
supportedCodecs.add(h264Codec);
factory = PeerConnectionFactory.builder()
.setVideoEncoderFactory(new CustomHardwareVideoEncoderFactory(supportedCodecs))
.setVideoDecoderFactory(new CustomHardwareVideoDecoderFactory(supportedCodecs))
.createPeerConnectionFactory();
PeerConnection.RTCConfiguration config =
new PeerConnection.RTCConfiguration(Collections.emptyList());
// RtpTranceiver is part of new unified plan semantics.
config.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN;
pc = factory.createPeerConnection(config, mock(PeerConnection.Observer.class));
}
/**
* Test that getRtpSenderCapabilities returns the codecs supported by the video encoder factory.
*/
@Test
@SmallTest
public void testGetSenderCapabilities() {
RtpCapabilities capabilities =
factory.getRtpSenderCapabilities(MediaStreamTrack.MediaType.MEDIA_TYPE_VIDEO);
List<String> codecNames = new ArrayList<>();
for (RtpCapabilities.CodecCapability codec : capabilities.getCodecs()) {
codecNames.add(codec.name);
}
assertTrue(codecNames.containsAll(Arrays.asList("VP8", "H264")));
}
/**
* Test that getRtpReceiverCapabilities returns the codecs supported by the video decoder factory.
*/
@Test
@SmallTest
public void testGetReceiverCapabilities() {
RtpCapabilities capabilities =
factory.getRtpReceiverCapabilities(MediaStreamTrack.MediaType.MEDIA_TYPE_VIDEO);
List<String> codecNames = new ArrayList<>();
for (RtpCapabilities.CodecCapability codec : capabilities.getCodecs()) {
codecNames.add(codec.name);
}
assertTrue(codecNames.containsAll(Arrays.asList("VP8", "H264")));
}
/**
* Test that a created offer reflects the codec capabilities passed into setCodecPreferences.
*/
@Test
@SmallTest
public void testSetCodecPreferences() {
List<Encoding> encodings = new ArrayList<>();
encodings.add(new Encoding("1", true, null));
RtpTransceiverInit init = new RtpTransceiverInit(
RtpTransceiver.RtpTransceiverDirection.SEND_ONLY, Collections.emptyList(), encodings);
RtpTransceiver transceiver =
pc.addTransceiver(MediaStreamTrack.MediaType.MEDIA_TYPE_VIDEO, init);
RtpCapabilities capabilities =
factory.getRtpSenderCapabilities(MediaStreamTrack.MediaType.MEDIA_TYPE_VIDEO);
RtpCapabilities.CodecCapability targetCodec = null;
for (RtpCapabilities.CodecCapability codec : capabilities.getCodecs()) {
if (codec.name.equals("VP8")) {
targetCodec = codec;
break;
}
}
assertNotNull(targetCodec);
transceiver.setCodecPreferences(Arrays.asList(targetCodec));
SdpObserverLatch sdpLatch = new SdpObserverLatch();
pc.createOffer(sdpLatch, new MediaConstraints());
assertTrue(sdpLatch.await());
SessionDescription offerSdp = sdpLatch.getSdp();
assertNotNull(offerSdp);
String[] sdpDescriptionLines = offerSdp.description.split("\r\n");
List<String> mediaDescriptions = getMediaDescriptions(sdpDescriptionLines);
assertEquals(1, mediaDescriptions.size());
List<String> payloads = getMediaPayloads(mediaDescriptions.get(0));
assertEquals(1, payloads.size());
String targetPayload = payloads.get(0);
List<String> rtpMaps = getRtpMaps(sdpDescriptionLines);
assertEquals(1, rtpMaps.size());
String rtpMap = rtpMaps.get(0);
String expected =
"a=rtpmap:" + targetPayload + " " + targetCodec.name + "/" + targetCodec.getClockRate();
assertEquals(expected, rtpMap);
}
private List<String> getMediaDescriptions(String[] sdpDescriptionLines) {
List<String> mediaDescriptions = new ArrayList<>();
for (String line : sdpDescriptionLines) {
if (line.charAt(0) == 'm') {
mediaDescriptions.add(line);
}
}
return mediaDescriptions;
}
private List<String> getMediaPayloads(String mediaDescription) {
String[] fields = mediaDescription.split(" ");
assertTrue(fields.length >= 4);
// Media formats are described from the fourth field onwards.
return Arrays.asList(Arrays.copyOfRange(fields, 3, fields.length));
}
private List<String> getRtpMaps(String[] sdpDescriptionLines) {
List<String> rtpMaps = new ArrayList<>();
for (String line : sdpDescriptionLines) {
if (line.startsWith("a=rtpmap")) {
rtpMaps.add(line);
}
}
return rtpMaps;
}
}

View File

@ -40,8 +40,10 @@
#include "sdk/android/src/jni/pc/android_network_monitor.h"
#include "sdk/android/src/jni/pc/audio.h"
#include "sdk/android/src/jni/pc/ice_candidate.h"
#include "sdk/android/src/jni/pc/media_stream_track.h"
#include "sdk/android/src/jni/pc/owned_factory_and_threads.h"
#include "sdk/android/src/jni/pc/peer_connection.h"
#include "sdk/android/src/jni/pc/rtp_capabilities.h"
#include "sdk/android/src/jni/pc/ssl_certificate_verifier_wrapper.h"
#include "sdk/android/src/jni/pc/video.h"
#include "system_wrappers/include/field_trial.h"
@ -393,6 +395,27 @@ jlong JNI_PeerConnectionFactory_CreateAudioTrack(
return jlongFromPointer(track.release());
}
ScopedJavaLocalRef<jobject> JNI_PeerConnectionFactory_GetRtpSenderCapabilities(
JNIEnv* jni,
jlong native_factory,
const JavaParamRef<jobject>& media_type) {
auto factory = PeerConnectionFactoryFromJava(native_factory);
return NativeToJavaRtpCapabilities(
jni, factory->GetRtpSenderCapabilities(
JavaToNativeMediaType(jni, media_type)));
}
ScopedJavaLocalRef<jobject>
JNI_PeerConnectionFactory_GetRtpReceiverCapabilities(
JNIEnv* jni,
jlong native_factory,
const JavaParamRef<jobject>& media_type) {
auto factory = PeerConnectionFactoryFromJava(native_factory);
return NativeToJavaRtpCapabilities(
jni, factory->GetRtpReceiverCapabilities(
JavaToNativeMediaType(jni, media_type)));
}
static jboolean JNI_PeerConnectionFactory_StartAecDump(
JNIEnv* jni,
jlong native_factory,

View File

@ -0,0 +1,119 @@
/*
* Copyright 2023 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.
*/
#include "sdk/android/src/jni/pc/rtp_capabilities.h"
#include "sdk/android/generated_peerconnection_jni/RtpCapabilities_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"
namespace webrtc {
namespace jni {
namespace {
ScopedJavaLocalRef<jobject> NativeToJavaRtpCodecParameter(
JNIEnv* env,
const RtpCodecCapability& codec) {
return Java_CodecCapability_Constructor(
env, codec.preferred_payload_type.value(),
NativeToJavaString(env, codec.name),
NativeToJavaMediaType(env, codec.kind),
NativeToJavaInteger(env, codec.clock_rate),
NativeToJavaInteger(env, codec.num_channels),
NativeToJavaString(env, codec.mime_type()),
NativeToJavaStringMap(env, codec.parameters));
}
ScopedJavaLocalRef<jobject> NativeToJavaRtpHeaderExtensionParameter(
JNIEnv* env,
const RtpHeaderExtensionCapability& extension) {
return Java_HeaderExtensionCapability_Constructor(
env, NativeToJavaString(env, extension.uri),
extension.preferred_id.value(), extension.preferred_encrypt);
}
} // namespace
RtpCapabilities JavaToNativeRtpCapabilities(
JNIEnv* jni,
const JavaRef<jobject>& j_capabilities) {
RtpCapabilities capabilities;
ScopedJavaLocalRef<jobject> j_header_extensions =
Java_RtpCapabilities_getHeaderExtensions(jni, j_capabilities);
for (const JavaRef<jobject>& j_header_extension :
Iterable(jni, j_header_extensions)) {
RtpHeaderExtensionCapability header_extension;
header_extension.uri = JavaToStdString(
jni, Java_HeaderExtensionCapability_getUri(jni, j_header_extension));
header_extension.preferred_id =
Java_HeaderExtensionCapability_getPreferredId(jni, j_header_extension);
header_extension.preferred_encrypt =
Java_HeaderExtensionCapability_getPreferredEncrypted(
jni, j_header_extension);
capabilities.header_extensions.push_back(header_extension);
}
// Convert codecs.
ScopedJavaLocalRef<jobject> j_codecs =
Java_RtpCapabilities_getCodecs(jni, j_capabilities);
for (const JavaRef<jobject>& j_codec : Iterable(jni, j_codecs)) {
RtpCodecCapability codec;
codec.preferred_payload_type =
Java_CodecCapability_getPreferredPayloadType(jni, j_codec);
codec.name =
JavaToStdString(jni, Java_CodecCapability_getName(jni, j_codec));
codec.kind =
JavaToNativeMediaType(jni, Java_CodecCapability_getKind(jni, j_codec));
codec.clock_rate = JavaToNativeOptionalInt(
jni, Java_CodecCapability_getClockRate(jni, j_codec));
codec.num_channels = JavaToNativeOptionalInt(
jni, Java_CodecCapability_getNumChannels(jni, j_codec));
auto parameters_map = JavaToNativeStringMap(
jni, Java_CodecCapability_getParameters(jni, j_codec));
codec.parameters.insert(parameters_map.begin(), parameters_map.end());
capabilities.codecs.push_back(codec);
}
return capabilities;
}
ScopedJavaLocalRef<jobject> NativeToJavaRtpCapabilities(
JNIEnv* env,
const RtpCapabilities& capabilities) {
return Java_RtpCapabilities_Constructor(
env,
NativeToJavaList(env, capabilities.codecs,
&NativeToJavaRtpCodecParameter),
NativeToJavaList(env, capabilities.header_extensions,
&NativeToJavaRtpHeaderExtensionParameter));
}
RtpCodecCapability JavaToNativeRtpCodecCapability(
JNIEnv* jni,
const JavaRef<jobject>& j_codec) {
RtpCodecCapability codec;
codec.preferred_payload_type =
Java_CodecCapability_getPreferredPayloadType(jni, j_codec);
codec.name = JavaToStdString(jni, Java_CodecCapability_getName(jni, j_codec));
codec.kind =
JavaToNativeMediaType(jni, Java_CodecCapability_getKind(jni, j_codec));
codec.clock_rate = JavaToNativeOptionalInt(
jni, Java_CodecCapability_getClockRate(jni, j_codec));
codec.num_channels = JavaToNativeOptionalInt(
jni, Java_CodecCapability_getNumChannels(jni, j_codec));
auto parameters_map = JavaToNativeStringMap(
jni, Java_CodecCapability_getParameters(jni, j_codec));
codec.parameters.insert(parameters_map.begin(), parameters_map.end());
return codec;
}
} // namespace jni
} // namespace webrtc

View File

@ -0,0 +1,37 @@
/*
* Copyright 2023 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.
*/
#ifndef SDK_ANDROID_SRC_JNI_PC_RTP_CAPABILITIES_H_
#define SDK_ANDROID_SRC_JNI_PC_RTP_CAPABILITIES_H_
#include <jni.h>
#include "api/rtp_parameters.h"
#include "sdk/android/native_api/jni/scoped_java_ref.h"
namespace webrtc {
namespace jni {
RtpCapabilities JavaToNativeRtpCapabilities(
JNIEnv* jni,
const JavaRef<jobject>& j_capabilities);
ScopedJavaLocalRef<jobject> NativeToJavaRtpCapabilities(
JNIEnv* jni,
const RtpCapabilities& capabilities);
RtpCodecCapability JavaToNativeRtpCodecCapability(
JNIEnv* jni,
const JavaRef<jobject>& j_codec_capability);
} // namespace jni
} // namespace webrtc
#endif // SDK_ANDROID_SRC_JNI_PC_RTP_CAPABILITIES_H_

View File

@ -16,6 +16,7 @@
#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"
#include "sdk/android/src/jni/pc/rtp_capabilities.h"
#include "sdk/android/src/jni/pc/rtp_parameters.h"
#include "sdk/android/src/jni/pc/rtp_receiver.h"
#include "sdk/android/src/jni/pc/rtp_sender.h"
@ -139,6 +140,17 @@ ScopedJavaLocalRef<jobject> JNI_RtpTransceiver_CurrentDirection(
: nullptr;
}
void JNI_RtpTransceiver_SetCodecPreferences(
JNIEnv* jni,
jlong j_rtp_transceiver_pointer,
const JavaParamRef<jobject>& j_codecs) {
std::vector<RtpCodecCapability> codecs =
JavaListToNativeVector<RtpCodecCapability, jobject>(
jni, j_codecs, &JavaToNativeRtpCodecCapability);
reinterpret_cast<RtpTransceiverInterface*>(j_rtp_transceiver_pointer)
->SetCodecPreferences(codecs);
}
void JNI_RtpTransceiver_StopInternal(JNIEnv* jni,
jlong j_rtp_transceiver_pointer) {
reinterpret_cast<RtpTransceiverInterface*>(j_rtp_transceiver_pointer)