Expose getCapabilities/setCodecPreferences for objc

Bug: None
Change-Id: I31cf22bae595cf2b995ff648523d25485106fcd5
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/305200
Reviewed-by: Magnus Jedvert <magjed@webrtc.org>
Reviewed-by: Peter Hanspers <peterhanspers@webrtc.org>
Commit-Queue: Peter Hanspers <peterhanspers@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40841}
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index 4f5ceb5..f86c1ec 100644
--- a/sdk/BUILD.gn
+++ b/sdk/BUILD.gn
@@ -991,6 +991,12 @@
         "objc/api/peerconnection/RTCRtcpParameters+Private.h",
         "objc/api/peerconnection/RTCRtcpParameters.h",
         "objc/api/peerconnection/RTCRtcpParameters.mm",
+        "objc/api/peerconnection/RTCRtpCapabilities+Private.h",
+        "objc/api/peerconnection/RTCRtpCapabilities.h",
+        "objc/api/peerconnection/RTCRtpCapabilities.mm",
+        "objc/api/peerconnection/RTCRtpCodecCapability+Private.h",
+        "objc/api/peerconnection/RTCRtpCodecCapability.h",
+        "objc/api/peerconnection/RTCRtpCodecCapability.mm",
         "objc/api/peerconnection/RTCRtpCodecParameters+Private.h",
         "objc/api/peerconnection/RTCRtpCodecParameters.h",
         "objc/api/peerconnection/RTCRtpCodecParameters.mm",
@@ -1309,6 +1315,8 @@
           "objc/api/peerconnection/RTCPeerConnectionFactory.h",
           "objc/api/peerconnection/RTCPeerConnectionFactoryOptions.h",
           "objc/api/peerconnection/RTCRtcpParameters.h",
+          "objc/api/peerconnection/RTCRtpCapabilities.h",
+          "objc/api/peerconnection/RTCRtpCodecCapability.h",
           "objc/api/peerconnection/RTCRtpCodecParameters.h",
           "objc/api/peerconnection/RTCRtpEncodingParameters.h",
           "objc/api/peerconnection/RTCRtpHeaderExtension.h",
@@ -1423,6 +1431,8 @@
           "objc/api/peerconnection/RTCPeerConnectionFactory.h",
           "objc/api/peerconnection/RTCPeerConnectionFactoryOptions.h",
           "objc/api/peerconnection/RTCRtcpParameters.h",
+          "objc/api/peerconnection/RTCRtpCapabilities.h",
+          "objc/api/peerconnection/RTCRtpCodecCapability.h",
           "objc/api/peerconnection/RTCRtpCodecParameters.h",
           "objc/api/peerconnection/RTCRtpEncodingParameters.h",
           "objc/api/peerconnection/RTCRtpHeaderExtension.h",
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.h b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.h
index 5575af9..41d1ab1 100644
--- a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.h
+++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.h
@@ -23,6 +23,8 @@
 @class RTC_OBJC_TYPE(RTCVideoSource);
 @class RTC_OBJC_TYPE(RTCVideoTrack);
 @class RTC_OBJC_TYPE(RTCPeerConnectionFactoryOptions);
+@class RTC_OBJC_TYPE(RTCRtpCapabilities);
+typedef NS_ENUM(NSInteger, RTCRtpMediaType);
 @protocol RTC_OBJC_TYPE
 (RTCPeerConnectionDelegate);
 @protocol RTC_OBJC_TYPE
@@ -99,6 +101,12 @@
                     (id<RTC_OBJC_TYPE(RTCSSLCertificateVerifier)>)certificateVerifier
                            delegate:(nullable id<RTC_OBJC_TYPE(RTCPeerConnectionDelegate)>)delegate;
 
+/** Returns the capabilities of an RTP sender for a specific mediaType. */
+- (RTC_OBJC_TYPE(RTCRtpCapabilities) *)rtpSenderCapabilitiesFor:(RTCRtpMediaType)mediaType;
+
+/** Returns the capabilities of an RTP receiver for a specific mediaType. */
+- (RTC_OBJC_TYPE(RTCRtpCapabilities) *)rtpReceiverCapabilitiesFor:(RTCRtpMediaType)mediaType;
+
 /** Set the options to be used for subsequently created RTCPeerConnections */
 - (void)setOptions:(nonnull RTC_OBJC_TYPE(RTCPeerConnectionFactoryOptions) *)options;
 
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm
index 62b5554..fe77ff1 100644
--- a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm
+++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm
@@ -19,6 +19,10 @@
 #import "RTCMediaConstraints+Private.h"
 #import "RTCMediaStream+Private.h"
 #import "RTCPeerConnection+Private.h"
+#import "RTCRtpCapabilities+Private.h"
+#import "RTCRtpCodecCapability+Private.h"
+#import "RTCRtpReceiver+Private.h"
+#import "RTCRtpSender+Private.h"
 #import "RTCVideoSource+Private.h"
 #import "RTCVideoTrack+Private.h"
 #import "base/RTCLogging.h"
@@ -303,6 +307,18 @@
                                                                delegate:delegate];
 }
 
+- (RTC_OBJC_TYPE(RTCRtpCapabilities) *)rtpSenderCapabilitiesFor:(RTCRtpMediaType)mediaType {
+  webrtc::RtpCapabilities capabilities = _nativeFactory->GetRtpSenderCapabilities(
+      [RTCRtpReceiver nativeMediaTypeForMediaType:mediaType]);
+  return [[RTCRtpCapabilities alloc] initWithNativeCapabilities:capabilities];
+}
+
+- (RTC_OBJC_TYPE(RTCRtpCapabilities) *)rtpReceiverCapabilitiesFor:(RTCRtpMediaType)mediaType {
+  webrtc::RtpCapabilities capabilities = _nativeFactory->GetRtpReceiverCapabilities(
+      [RTCRtpReceiver nativeMediaTypeForMediaType:mediaType]);
+  return [[RTCRtpCapabilities alloc] initWithNativeCapabilities:capabilities];
+}
+
 - (void)setOptions:(nonnull RTC_OBJC_TYPE(RTCPeerConnectionFactoryOptions) *)options {
   RTC_DCHECK(options != nil);
   _nativeFactory->SetOptions(options.nativeOptions);
diff --git a/sdk/objc/api/peerconnection/RTCRtpCapabilities+Private.h b/sdk/objc/api/peerconnection/RTCRtpCapabilities+Private.h
new file mode 100644
index 0000000..3ccfe58
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpCapabilities+Private.h
@@ -0,0 +1,29 @@
+/*
+ *  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.
+ */
+
+#import "RTCRtpCapabilities.h"
+
+#include "api/rtp_parameters.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTC_OBJC_TYPE (RTCRtpCapabilities)
+()
+
+    /** Returns the equivalent native RtpCapabilities structure. */
+    @property(nonatomic, readonly) webrtc::RtpCapabilities nativeCapabilities;
+
+/** Initialize the object with a native RtpCapabilities structure. */
+- (instancetype)initWithNativeCapabilities:(const webrtc::RtpCapabilities &)nativeCapabilities
+    NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCRtpCapabilities.h b/sdk/objc/api/peerconnection/RTCRtpCapabilities.h
new file mode 100644
index 0000000..ebeb8ed
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpCapabilities.h
@@ -0,0 +1,28 @@
+/*
+ *  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.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "RTCMacros.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class RTC_OBJC_TYPE(RTCRtpCodecCapability);
+
+RTC_OBJC_EXPORT
+@interface RTC_OBJC_TYPE (RTCRtpCapabilities) : NSObject
+
+- (instancetype)init NS_UNAVAILABLE;
+
+@property(nonatomic, readonly) NSArray<RTC_OBJC_TYPE(RTCRtpCodecCapability) *> *codecs;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCRtpCapabilities.mm b/sdk/objc/api/peerconnection/RTCRtpCapabilities.mm
new file mode 100644
index 0000000..5005e5b
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpCapabilities.mm
@@ -0,0 +1,44 @@
+/*
+ *  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.
+ */
+
+#import "RTCRtpCapabilities+Private.h"
+#import "RTCRtpCodecCapability+Private.h"
+
+#import "RTCMediaStreamTrack.h"
+#import "helpers/NSString+StdString.h"
+
+#include "media/base/media_constants.h"
+#include "rtc_base/checks.h"
+
+@implementation RTC_OBJC_TYPE (RTCRtpCapabilities)
+
+@synthesize nativeCapabilities = _nativeCapabilities;
+
+- (instancetype)initWithNativeCapabilities:(const webrtc::RtpCapabilities &)nativeCapabilities {
+  if (self = [super init]) {
+    _nativeCapabilities = nativeCapabilities;
+  }
+
+  return self;
+}
+
+- (NSArray<RTC_OBJC_TYPE(RTCRtpCodecCapability) *> *)codecs {
+  NSMutableArray *result = [NSMutableArray array];
+
+  for (auto &element : _nativeCapabilities.codecs) {
+    RTCRtpCodecCapability *object =
+        [[RTCRtpCodecCapability alloc] initWithNativeCodecCapability:element];
+    [result addObject:object];
+  }
+
+  return result;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCRtpCodecCapability+Private.h b/sdk/objc/api/peerconnection/RTCRtpCodecCapability+Private.h
new file mode 100644
index 0000000..ee578d7
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpCodecCapability+Private.h
@@ -0,0 +1,27 @@
+/*
+ *  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.
+ */
+
+#import "RTCRtpCodecCapability.h"
+
+#include "api/rtp_parameters.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTC_OBJC_TYPE (RTCRtpCodecCapability)
+()
+
+    @property(nonatomic, readonly) webrtc::RtpCodecCapability nativeCodecCapability;
+
+- (instancetype)initWithNativeCodecCapability:
+    (const webrtc::RtpCodecCapability &)nativeCodecCapability NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCRtpCodecCapability.h b/sdk/objc/api/peerconnection/RTCRtpCodecCapability.h
new file mode 100644
index 0000000..0d60761
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpCodecCapability.h
@@ -0,0 +1,54 @@
+/*
+ *  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.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "RTCMacros.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef NS_ENUM(NSInteger, RTCRtpMediaType);
+
+RTC_OBJC_EXPORT
+@interface RTC_OBJC_TYPE (RTCRtpCodecCapability) : NSObject
+
+/** Build MIME "type/subtype" string from name and kind. */
+@property(nonatomic, readonly) NSString *mimeType;
+
+/** Used to identify the codec. Equivalent to MIME subtype. */
+@property(nonatomic, copy) NSString *name;
+
+/** The media type of this codec. Equivalent to MIME top-level type. */
+@property(nonatomic, assign) RTCRtpMediaType kind;
+
+/** Clock rate in Hertz. If unset, the codec is applicable to any clock rate. */
+@property(nonatomic, copy, nullable) NSNumber *clockRate;
+
+/** Default payload type for this codec. Mainly needed for codecs that use
+ *  that have statically assigned payload types.
+ */
+@property(nonatomic, copy, nullable) NSNumber *preferredPayloadType;
+
+/** The number of audio channels supported. Unused for video codecs. */
+@property(nonatomic, copy, nullable) NSNumber *numChannels;
+
+/**Codec-specific parameters that must be signaled to the remote party.
+ *
+ * Corresponds to "a=fmtp" parameters in SDP.
+ *
+ * Contrary to ORTC, these parameters are named using all lowercase strings.
+ * This helps make the mapping to SDP simpler, if an application is using SDP.
+ * Boolean values are represented by the string "1".
+ */
+@property(nonatomic, copy) NSDictionary<NSString *, NSString *> *parameters;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCRtpCodecCapability.mm b/sdk/objc/api/peerconnection/RTCRtpCodecCapability.mm
new file mode 100644
index 0000000..bb48ade
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpCodecCapability.mm
@@ -0,0 +1,132 @@
+/*
+ *  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.
+ */
+
+#import "RTCRtpCodecCapability+Private.h"
+
+#import "RTCRtpReceiver+Private.h"
+
+#import "RTCMediaStreamTrack.h"
+#import "helpers/NSString+StdString.h"
+
+#include "media/base/media_constants.h"
+#include "rtc_base/checks.h"
+
+@implementation RTC_OBJC_TYPE (RTCRtpCodecCapability)
+
+@synthesize nativeCodecCapability = _nativeCodecCapability;
+
+- (instancetype)init {
+  return [self initWithNativeCodecCapability:webrtc::RtpCodecCapability()];
+}
+
+- (instancetype)initWithNativeCodecCapability:
+    (const webrtc::RtpCodecCapability &)nativeCodecCapability {
+  if (self = [super init]) {
+    _nativeCodecCapability = nativeCodecCapability;
+  }
+
+  return self;
+}
+
+- (NSString *)mimeType {
+  return [NSString stringWithUTF8String:_nativeCodecCapability.mime_type().c_str()];
+}
+
+- (NSString *)name {
+  return [NSString stringWithUTF8String:_nativeCodecCapability.name.c_str()];
+}
+
+- (void)setName:(NSString *)name {
+  _nativeCodecCapability.name = std::string([name UTF8String]);
+}
+
+- (RTCRtpMediaType)kind {
+  return [RTCRtpReceiver mediaTypeForNativeMediaType:_nativeCodecCapability.kind];
+}
+
+- (void)setKind:(RTCRtpMediaType)kind {
+  _nativeCodecCapability.kind = [RTCRtpReceiver nativeMediaTypeForMediaType:kind];
+}
+
+- (NSNumber *)clockRate {
+  if (!_nativeCodecCapability.clock_rate) {
+    return nil;
+  }
+
+  return [NSNumber numberWithInt:*_nativeCodecCapability.clock_rate];
+}
+
+- (void)setClockRate:(NSNumber *)clockRate {
+  if (clockRate == nil) {
+    _nativeCodecCapability.clock_rate = absl::optional<int>();
+    return;
+  }
+
+  _nativeCodecCapability.clock_rate = absl::optional<int>(clockRate.intValue);
+}
+
+- (NSNumber *)preferredPayloadType {
+  if (!_nativeCodecCapability.preferred_payload_type) {
+    return nil;
+  }
+
+  return [NSNumber numberWithInt:*_nativeCodecCapability.preferred_payload_type];
+}
+
+- (void)setPreferredPayloadType:(NSNumber *)preferredPayloadType {
+  if (preferredPayloadType == nil) {
+    _nativeCodecCapability.preferred_payload_type = absl::optional<int>();
+    return;
+  }
+
+  _nativeCodecCapability.preferred_payload_type =
+      absl::optional<int>(preferredPayloadType.intValue);
+}
+
+- (NSNumber *)numChannels {
+  if (!_nativeCodecCapability.num_channels) {
+    return nil;
+  }
+
+  return [NSNumber numberWithInt:*_nativeCodecCapability.num_channels];
+}
+
+- (void)setNumChannels:(NSNumber *)numChannels {
+  if (numChannels == nil) {
+    _nativeCodecCapability.num_channels = absl::optional<int>();
+    return;
+  }
+
+  _nativeCodecCapability.num_channels = absl::optional<int>(numChannels.intValue);
+}
+
+- (NSDictionary<NSString *, NSString *> *)parameters {
+  NSMutableDictionary *result = [NSMutableDictionary dictionary];
+  auto _parameters = _nativeCodecCapability.parameters;
+  for (auto it = _parameters.begin(); it != _parameters.end(); ++it) {
+    [result setObject:[NSString stringForStdString:it->second]
+               forKey:[NSString stringForStdString:it->first]];
+  }
+
+  return result;
+}
+
+- (void)setParameters:(NSDictionary<NSString *, NSString *> *)parameters {
+  std::map<std::string, std::string> _parameters;
+  for (NSString *paramKey in parameters.allKeys) {
+    std::string key = [NSString stdStringForString:paramKey];
+    std::string value = [NSString stdStringForString:parameters[paramKey]];
+    _parameters[key] = value;
+  }
+
+  _nativeCodecCapability.parameters = _parameters;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCRtpTransceiver.h b/sdk/objc/api/peerconnection/RTCRtpTransceiver.h
index fd59013..a10a260 100644
--- a/sdk/objc/api/peerconnection/RTCRtpTransceiver.h
+++ b/sdk/objc/api/peerconnection/RTCRtpTransceiver.h
@@ -16,6 +16,8 @@
 
 NS_ASSUME_NONNULL_BEGIN
 
+@class RTC_OBJC_TYPE(RTCRtpCodecCapability);
+
 extern NSString *const kRTCRtpTransceiverErrorDomain;
 
 /** https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiverdirection */
@@ -104,6 +106,13 @@
  */
 @property(nonatomic, readonly) RTCRtpTransceiverDirection direction;
 
+/** The codecPreferences indicates any overridden codec preferences, which
+ *  will be used in calls to createOffer and createAnswer. An empty array
+ *  indicates that the default codec preferences will be used.
+ *  https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-setcodecpreferences
+ */
+@property(nonatomic, readonly) NSArray<RTC_OBJC_TYPE(RTCRtpCodecCapability) *> *codecPreferences;
+
 /** The currentDirection attribute indicates the current direction negotiated
  *  for this transceiver. If this transceiver has never been represented in an
  *  offer/answer exchange, or if the transceiver is stopped, the value is not
@@ -125,6 +134,15 @@
  */
 - (void)setDirection:(RTCRtpTransceiverDirection)direction error:(NSError **)error;
 
+/** The setCodecPreferences method will reject attempts to set codecs not
+ *  matching codecs found in sender or receiver capabilities for kind, where
+ *  kind is the mediaType of the RTCRtpTransceiver on which the method is
+ *  called.
+ *  https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-setcodecpreferences
+ */
+- (void)setCodecPreferences:(NSArray<RTC_OBJC_TYPE(RTCRtpCodecCapability) *> *)codecPreferences
+                      error:(NSError **)error;
+
 @end
 
 RTC_OBJC_EXPORT
diff --git a/sdk/objc/api/peerconnection/RTCRtpTransceiver.mm b/sdk/objc/api/peerconnection/RTCRtpTransceiver.mm
index ae1cf79..36834ea 100644
--- a/sdk/objc/api/peerconnection/RTCRtpTransceiver.mm
+++ b/sdk/objc/api/peerconnection/RTCRtpTransceiver.mm
@@ -10,6 +10,8 @@
 
 #import "RTCRtpTransceiver+Private.h"
 
+#import "RTCRtpCodecCapability+Private.h"
+#import "RTCRtpCodecCapability.h"
 #import "RTCRtpEncodingParameters+Private.h"
 #import "RTCRtpParameters+Private.h"
 #import "RTCRtpReceiver+Private.h"
@@ -65,6 +67,40 @@
   }
 }
 
+- (NSArray<RTC_OBJC_TYPE(RTCRtpCodecCapability) *> *)codecPreferences {
+  NSMutableArray *result = [NSMutableArray array];
+  std::vector<webrtc::RtpCodecCapability> capabilities = _nativeRtpTransceiver->codec_preferences();
+
+  for (auto &element : capabilities) {
+    RTCRtpCodecCapability *object =
+        [[RTCRtpCodecCapability alloc] initWithNativeCodecCapability:element];
+    [result addObject:object];
+  }
+
+  return result;
+}
+
+- (void)setCodecPreferences:(NSArray<RTC_OBJC_TYPE(RTCRtpCodecCapability) *> *)codecPreferences
+                      error:(NSError **)error {
+  std::vector<webrtc::RtpCodecCapability> objects;
+
+  for (RTCRtpCodecCapability *object in codecPreferences) {
+    objects.push_back(object.nativeCodecCapability);
+  }
+
+  webrtc::RTCError nativeError = _nativeRtpTransceiver->SetCodecPreferences(
+      rtc::ArrayView<webrtc::RtpCodecCapability>(objects.data(), objects.size()));
+
+  if (!nativeError.ok() && error) {
+    *error = [NSError errorWithDomain:kRTCRtpTransceiverErrorDomain
+                                 code:static_cast<int>(nativeError.type())
+                             userInfo:@{
+                               @"message" : [NSString stringWithCString:nativeError.message()
+                                                               encoding:NSUTF8StringEncoding]
+                             }];
+  }
+}
+
 @synthesize sender = _sender;
 @synthesize receiver = _receiver;