Expose setCodecPreferences/getCapabilities for iOS
Bug: webrtc:15749 Change-Id: I92f5d5dc5d9eb4d0a60c33ed724a0d3e8b4fa1a8 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/333402 Auto-Submit: Karim Ham <karim@karhm.com> Reviewed-by: Florent Castelli <orphis@webrtc.org> Reviewed-by: Peter Hanspers <peterhanspers@webrtc.org> Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org> Commit-Queue: Florent Castelli <orphis@webrtc.org> Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org> Cr-Commit-Position: refs/heads/main@{#41601}
This commit is contained in:
parent
c708c00f95
commit
1b61c7161e
1
AUTHORS
1
AUTHORS
@ -65,6 +65,7 @@ Jie Mao <maojie0924@gmail.com>
|
||||
Jiwon Kim <jwkim0000@gmail.com>
|
||||
Johnny Wong <hellojinqiang@gmail.com>
|
||||
Jose Antonio Olivera Ortega <josea.olivera@gmail.com>
|
||||
Karim Hammache <karim@karhm.com>
|
||||
Keiichi Enomoto <enm10k@gmail.com>
|
||||
Kiran Thind <kiran.thind@gmail.com>
|
||||
Korniltsev Anatoly <korniltsev.anatoly@gmail.com>
|
||||
|
||||
15
sdk/BUILD.gn
15
sdk/BUILD.gn
@ -991,6 +991,12 @@ if (is_ios || is_mac) {
|
||||
"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",
|
||||
@ -1000,6 +1006,9 @@ if (is_ios || is_mac) {
|
||||
"objc/api/peerconnection/RTCRtpHeaderExtension+Private.h",
|
||||
"objc/api/peerconnection/RTCRtpHeaderExtension.h",
|
||||
"objc/api/peerconnection/RTCRtpHeaderExtension.mm",
|
||||
"objc/api/peerconnection/RTCRtpHeaderExtensionCapability+Private.h",
|
||||
"objc/api/peerconnection/RTCRtpHeaderExtensionCapability.h",
|
||||
"objc/api/peerconnection/RTCRtpHeaderExtensionCapability.mm",
|
||||
"objc/api/peerconnection/RTCRtpParameters+Private.h",
|
||||
"objc/api/peerconnection/RTCRtpParameters.h",
|
||||
"objc/api/peerconnection/RTCRtpParameters.mm",
|
||||
@ -1309,9 +1318,12 @@ if (is_ios || is_mac) {
|
||||
"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",
|
||||
"objc/api/peerconnection/RTCRtpHeaderExtensionCapability.h",
|
||||
"objc/api/peerconnection/RTCRtpParameters.h",
|
||||
"objc/api/peerconnection/RTCRtpReceiver.h",
|
||||
"objc/api/peerconnection/RTCRtpSender.h",
|
||||
@ -1423,9 +1435,12 @@ if (is_ios || is_mac) {
|
||||
"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",
|
||||
"objc/api/peerconnection/RTCRtpHeaderExtensionCapability.h",
|
||||
"objc/api/peerconnection/RTCRtpParameters.h",
|
||||
"objc/api/peerconnection/RTCRtpReceiver.h",
|
||||
"objc/api/peerconnection/RTCRtpSender.h",
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class RTC_OBJC_TYPE(RTCRtpCapabilities);
|
||||
@class RTC_OBJC_TYPE(RTCAudioSource);
|
||||
@class RTC_OBJC_TYPE(RTCAudioTrack);
|
||||
@class RTC_OBJC_TYPE(RTCConfiguration);
|
||||
@ -51,6 +52,18 @@ RTC_OBJC_EXPORT
|
||||
decoderFactory:(nullable id<RTC_OBJC_TYPE(RTCVideoDecoderFactory)>)decoderFactory
|
||||
audioDevice:(nullable id<RTC_OBJC_TYPE(RTCAudioDevice)>)audioDevice;
|
||||
|
||||
/**
|
||||
* Valid kind values are kRTCMediaStreamTrackKindAudio and
|
||||
* kRTCMediaStreamTrackKindVideo.
|
||||
*/
|
||||
- (RTC_OBJC_TYPE(RTCRtpCapabilities) *)rtpSenderCapabilitiesForKind:(NSString *)kind;
|
||||
|
||||
/**
|
||||
* Valid kind values are kRTCMediaStreamTrackKindAudio and
|
||||
* kRTCMediaStreamTrackKindVideo.
|
||||
*/
|
||||
- (RTC_OBJC_TYPE(RTCRtpCapabilities) *)rtpReceiverCapabilitiesForKind:(NSString *)kind;
|
||||
|
||||
/** Initialize an RTCAudioSource with constraints. */
|
||||
- (RTC_OBJC_TYPE(RTCAudioSource) *)audioSourceWithConstraints:
|
||||
(nullable RTC_OBJC_TYPE(RTCMediaConstraints) *)constraints;
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
#import "RTCPeerConnectionFactory+Native.h"
|
||||
#import "RTCPeerConnectionFactory+Private.h"
|
||||
#import "RTCPeerConnectionFactoryOptions+Private.h"
|
||||
#import "RTCRtpCapabilities+Private.h"
|
||||
|
||||
#import "RTCAudioSource+Private.h"
|
||||
#import "RTCAudioTrack+Private.h"
|
||||
@ -38,6 +39,7 @@
|
||||
#include "api/transport/field_trial_based_config.h"
|
||||
#import "components/video_codec/RTCVideoDecoderFactoryH264.h"
|
||||
#import "components/video_codec/RTCVideoEncoderFactoryH264.h"
|
||||
#include "media/base/media_constants.h"
|
||||
#include "modules/audio_device/include/audio_device.h"
|
||||
#include "modules/audio_processing/include/audio_processing.h"
|
||||
|
||||
@ -214,6 +216,20 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (RTC_OBJC_TYPE(RTCRtpCapabilities) *)rtpSenderCapabilitiesForKind:(NSString *)kind {
|
||||
cricket::MediaType mediaType = [[self class] mediaTypeForKind:kind];
|
||||
|
||||
webrtc::RtpCapabilities rtpCapabilities = _nativeFactory->GetRtpSenderCapabilities(mediaType);
|
||||
return [[RTC_OBJC_TYPE(RTCRtpCapabilities) alloc] initWithNativeRtpCapabilities:rtpCapabilities];
|
||||
}
|
||||
|
||||
- (RTC_OBJC_TYPE(RTCRtpCapabilities) *)rtpReceiverCapabilitiesForKind:(NSString *)kind {
|
||||
cricket::MediaType mediaType = [[self class] mediaTypeForKind:kind];
|
||||
|
||||
webrtc::RtpCapabilities rtpCapabilities = _nativeFactory->GetRtpReceiverCapabilities(mediaType);
|
||||
return [[RTC_OBJC_TYPE(RTCRtpCapabilities) alloc] initWithNativeRtpCapabilities:rtpCapabilities];
|
||||
}
|
||||
|
||||
- (RTC_OBJC_TYPE(RTCAudioSource) *)audioSourceWithConstraints:
|
||||
(nullable RTC_OBJC_TYPE(RTCMediaConstraints) *)constraints {
|
||||
std::unique_ptr<webrtc::MediaConstraints> nativeConstraints;
|
||||
@ -338,4 +354,17 @@
|
||||
return _networkThread.get();
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
+ (cricket::MediaType)mediaTypeForKind:(NSString *)kind {
|
||||
if (kind == kRTCMediaStreamTrackKindAudio) {
|
||||
return cricket::MEDIA_TYPE_AUDIO;
|
||||
} else if (kind == kRTCMediaStreamTrackKindVideo) {
|
||||
return cricket::MEDIA_TYPE_VIDEO;
|
||||
} else {
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
return cricket::MEDIA_TYPE_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
32
sdk/objc/api/peerconnection/RTCRtpCapabilities+Private.h
Normal file
32
sdk/objc/api/peerconnection/RTCRtpCapabilities+Private.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
|
||||
#import "RTCRtpCapabilities.h"
|
||||
|
||||
#include "api/rtp_parameters.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface RTC_OBJC_TYPE (RTCRtpCapabilities)()
|
||||
|
||||
/**
|
||||
* The native RtpCapabilities representation of this RTCRtpCapabilities
|
||||
* object. This is needed to pass to the underlying C++ APIs.
|
||||
*/
|
||||
@property(nonatomic, readonly) webrtc::RtpCapabilities nativeRtpCapabilities;
|
||||
|
||||
/**
|
||||
* Initialize an RTCRtpCapabilities from a native RtpCapabilities.
|
||||
*/
|
||||
- (instancetype)initWithNativeRtpCapabilities:(const webrtc::RtpCapabilities &)rtpCapabilities;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
31
sdk/objc/api/peerconnection/RTCRtpCapabilities.h
Normal file
31
sdk/objc/api/peerconnection/RTCRtpCapabilities.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "RTCMacros.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class RTC_OBJC_TYPE(RTCRtpCodecCapability);
|
||||
@class RTC_OBJC_TYPE(RTCRtpHeaderExtensionCapability);
|
||||
|
||||
RTC_OBJC_EXPORT
|
||||
@interface RTC_OBJC_TYPE (RTCRtpCapabilities) : NSObject
|
||||
|
||||
@property(nonatomic, copy) NSArray<RTC_OBJC_TYPE(RTCRtpCodecCapability) *> *codecs;
|
||||
@property(nonatomic, copy)
|
||||
NSArray<RTC_OBJC_TYPE(RTCRtpHeaderExtensionCapability) *> *headerExtensions;
|
||||
|
||||
- (instancetype)init;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
60
sdk/objc/api/peerconnection/RTCRtpCapabilities.mm
Normal file
60
sdk/objc/api/peerconnection/RTCRtpCapabilities.mm
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
|
||||
#import "RTCRtpCapabilities+Private.h"
|
||||
|
||||
#import "RTCRtpCodecCapability+Private.h"
|
||||
#import "RTCRtpHeaderExtensionCapability+Private.h"
|
||||
|
||||
#import "base/RTCLogging.h"
|
||||
#import "helpers/NSString+StdString.h"
|
||||
|
||||
@implementation RTC_OBJC_TYPE (RTCRtpCapabilities)
|
||||
|
||||
@synthesize codecs = _codecs;
|
||||
@synthesize headerExtensions = _headerExtensions;
|
||||
|
||||
- (instancetype)init {
|
||||
webrtc::RtpCapabilities nativeRtpCapabilities;
|
||||
return [self initWithNativeRtpCapabilities:nativeRtpCapabilities];
|
||||
}
|
||||
|
||||
- (instancetype)initWithNativeRtpCapabilities:
|
||||
(const webrtc::RtpCapabilities &)nativeRtpCapabilities {
|
||||
if (self = [super init]) {
|
||||
NSMutableArray *codecs = [[NSMutableArray alloc] init];
|
||||
for (const auto &codec : nativeRtpCapabilities.codecs) {
|
||||
[codecs addObject:[[RTC_OBJC_TYPE(RTCRtpCodecCapability) alloc]
|
||||
initWithNativeRtpCodecCapability:codec]];
|
||||
}
|
||||
_codecs = codecs;
|
||||
|
||||
NSMutableArray *headerExtensions = [[NSMutableArray alloc] init];
|
||||
for (const auto &headerExtension : nativeRtpCapabilities.header_extensions) {
|
||||
[headerExtensions addObject:[[RTC_OBJC_TYPE(RTCRtpHeaderExtensionCapability) alloc]
|
||||
initWithNativeRtpHeaderExtensionCapability:headerExtension]];
|
||||
}
|
||||
_headerExtensions = headerExtensions;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (webrtc::RtpCapabilities)nativeRtpCapabilities {
|
||||
webrtc::RtpCapabilities rtpCapabilities;
|
||||
for (RTC_OBJC_TYPE(RTCRtpCodecCapability) * codec in _codecs) {
|
||||
rtpCapabilities.codecs.push_back(codec.nativeRtpCodecCapability);
|
||||
}
|
||||
for (RTC_OBJC_TYPE(RTCRtpHeaderExtensionCapability) * headerExtension in _headerExtensions) {
|
||||
rtpCapabilities.header_extensions.push_back(headerExtension.nativeRtpHeaderExtensionCapability);
|
||||
}
|
||||
return rtpCapabilities;
|
||||
}
|
||||
|
||||
@end
|
||||
33
sdk/objc/api/peerconnection/RTCRtpCodecCapability+Private.h
Normal file
33
sdk/objc/api/peerconnection/RTCRtpCodecCapability+Private.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
|
||||
#import "RTCRtpCodecCapability.h"
|
||||
|
||||
#include "api/rtp_parameters.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface RTC_OBJC_TYPE (RTCRtpCodecCapability)()
|
||||
|
||||
/**
|
||||
* The native RtpCodecCapability representation of this RTCRtpCodecCapability
|
||||
* object. This is needed to pass to the underlying C++ APIs.
|
||||
*/
|
||||
@property(nonatomic, readonly) webrtc::RtpCodecCapability nativeRtpCodecCapability;
|
||||
|
||||
/**
|
||||
* Initialize an RTCRtpCodecCapability from a native RtpCodecCapability.
|
||||
*/
|
||||
- (instancetype)initWithNativeRtpCodecCapability:
|
||||
(const webrtc::RtpCodecCapability &)nativeRtpCodecCapability;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
58
sdk/objc/api/peerconnection/RTCRtpCodecCapability.h
Normal file
58
sdk/objc/api/peerconnection/RTCRtpCodecCapability.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "RTCMacros.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
RTC_OBJC_EXPORT
|
||||
@interface RTC_OBJC_TYPE (RTCRtpCodecCapability) : NSObject
|
||||
|
||||
/** The preferred RTP payload type. */
|
||||
@property(nonatomic, readonly, nullable) NSNumber *preferredPayloadType;
|
||||
|
||||
/**
|
||||
* The codec MIME subtype. Valid types are listed in:
|
||||
* http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-2
|
||||
*
|
||||
* Several supported types are represented by the constants above.
|
||||
*/
|
||||
@property(nonatomic, readonly) NSString *name;
|
||||
|
||||
/**
|
||||
* The media type of this codec. Equivalent to MIME top-level type.
|
||||
*
|
||||
* Valid values are kRTCMediaStreamTrackKindAudio and
|
||||
* kRTCMediaStreamTrackKindVideo.
|
||||
*/
|
||||
@property(nonatomic, readonly) NSString *kind;
|
||||
|
||||
/** The codec clock rate expressed in Hertz. */
|
||||
@property(nonatomic, readonly, nullable) NSNumber *clockRate;
|
||||
|
||||
/**
|
||||
* The number of audio channels (mono=1, stereo=2).
|
||||
* Set to null for video codecs.
|
||||
**/
|
||||
@property(nonatomic, readonly, nullable) NSNumber *numChannels;
|
||||
|
||||
/** The "format specific parameters" field from the "a=fmtp" line in the SDP */
|
||||
@property(nonatomic, readonly) NSDictionary<NSString *, NSString *> *parameters;
|
||||
|
||||
/** The MIME type of the codec. */
|
||||
@property(nonatomic, readonly) NSString *mimeType;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
116
sdk/objc/api/peerconnection/RTCRtpCodecCapability.mm
Normal file
116
sdk/objc/api/peerconnection/RTCRtpCodecCapability.mm
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
|
||||
#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 (RTCRtpCodecCapability)
|
||||
|
||||
@synthesize preferredPayloadType = _preferredPayloadType;
|
||||
@synthesize name = _name;
|
||||
@synthesize kind = _kind;
|
||||
@synthesize clockRate = _clockRate;
|
||||
@synthesize numChannels = _numChannels;
|
||||
@synthesize parameters = _parameters;
|
||||
@synthesize mimeType = _mimeType;
|
||||
|
||||
- (instancetype)init {
|
||||
webrtc::RtpCodecCapability rtpCodecCapability;
|
||||
return [self initWithNativeRtpCodecCapability:rtpCodecCapability];
|
||||
}
|
||||
|
||||
- (instancetype)initWithNativeRtpCodecCapability:
|
||||
(const webrtc::RtpCodecCapability &)nativeRtpCodecCapability {
|
||||
if (self = [super init]) {
|
||||
if (nativeRtpCodecCapability.preferred_payload_type) {
|
||||
_preferredPayloadType =
|
||||
[NSNumber numberWithInt:*nativeRtpCodecCapability.preferred_payload_type];
|
||||
}
|
||||
_name = [NSString stringForStdString:nativeRtpCodecCapability.name];
|
||||
switch (nativeRtpCodecCapability.kind) {
|
||||
case cricket::MEDIA_TYPE_AUDIO:
|
||||
_kind = kRTCMediaStreamTrackKindAudio;
|
||||
break;
|
||||
case cricket::MEDIA_TYPE_VIDEO:
|
||||
_kind = kRTCMediaStreamTrackKindVideo;
|
||||
break;
|
||||
case cricket::MEDIA_TYPE_DATA:
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
break;
|
||||
case cricket::MEDIA_TYPE_UNSUPPORTED:
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
break;
|
||||
}
|
||||
if (nativeRtpCodecCapability.clock_rate) {
|
||||
_clockRate = [NSNumber numberWithInt:*nativeRtpCodecCapability.clock_rate];
|
||||
}
|
||||
if (nativeRtpCodecCapability.num_channels) {
|
||||
_numChannels = [NSNumber numberWithInt:*nativeRtpCodecCapability.num_channels];
|
||||
}
|
||||
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
|
||||
for (const auto ¶meter : nativeRtpCodecCapability.parameters) {
|
||||
[parameters setObject:[NSString stringForStdString:parameter.second]
|
||||
forKey:[NSString stringForStdString:parameter.first]];
|
||||
}
|
||||
_parameters = parameters;
|
||||
_mimeType = [NSString stringForStdString:nativeRtpCodecCapability.mime_type()];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"RTC_OBJC_TYPE(RTCRtpCodecCapability) {\n "
|
||||
@"preferredPayloadType: %@\n name: %@\n kind: %@\n "
|
||||
@"clockRate: %@\n numChannels: %@\n parameters: %@\n "
|
||||
@"mimeType: %@\n}",
|
||||
_preferredPayloadType,
|
||||
_name,
|
||||
_kind,
|
||||
_clockRate,
|
||||
_numChannels,
|
||||
_parameters,
|
||||
_mimeType];
|
||||
}
|
||||
|
||||
- (webrtc::RtpCodecCapability)nativeRtpCodecCapability {
|
||||
webrtc::RtpCodecCapability rtpCodecCapability;
|
||||
if (_preferredPayloadType != nil) {
|
||||
rtpCodecCapability.preferred_payload_type = absl::optional<int>(_preferredPayloadType.intValue);
|
||||
}
|
||||
rtpCodecCapability.name = [NSString stdStringForString:_name];
|
||||
// NSString pointer comparison is safe here since "kind" is readonly and only
|
||||
// populated above.
|
||||
if (_kind == kRTCMediaStreamTrackKindAudio) {
|
||||
rtpCodecCapability.kind = cricket::MEDIA_TYPE_AUDIO;
|
||||
} else if (_kind == kRTCMediaStreamTrackKindVideo) {
|
||||
rtpCodecCapability.kind = cricket::MEDIA_TYPE_VIDEO;
|
||||
} else {
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
}
|
||||
if (_clockRate != nil) {
|
||||
rtpCodecCapability.clock_rate = absl::optional<int>(_clockRate.intValue);
|
||||
}
|
||||
if (_numChannels != nil) {
|
||||
rtpCodecCapability.num_channels = absl::optional<int>(_numChannels.intValue);
|
||||
}
|
||||
for (NSString *paramKey in _parameters.allKeys) {
|
||||
std::string key = [NSString stdStringForString:paramKey];
|
||||
std::string value = [NSString stdStringForString:_parameters[paramKey]];
|
||||
rtpCodecCapability.parameters[key] = value;
|
||||
}
|
||||
return rtpCodecCapability;
|
||||
}
|
||||
|
||||
@end
|
||||
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
|
||||
#import "RTCRtpHeaderExtensionCapability.h"
|
||||
|
||||
#include "api/rtp_parameters.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface RTC_OBJC_TYPE (RTCRtpHeaderExtensionCapability)()
|
||||
|
||||
/**
|
||||
* The native RtpHeaderExtensionCapability representation of this
|
||||
* RTCRtpHeaderExtensionCapability object. This is needed to pass to the underlying C++ APIs.
|
||||
*/
|
||||
@property(nonatomic,
|
||||
readonly) webrtc::RtpHeaderExtensionCapability nativeRtpHeaderExtensionCapability;
|
||||
|
||||
/**
|
||||
* Initialize an RTCRtpHeaderExtensionCapability from a native RtpHeaderExtensionCapability.
|
||||
*/
|
||||
- (instancetype)initWithNativeRtpHeaderExtensionCapability:
|
||||
(const webrtc::RtpHeaderExtensionCapability &)rtpHeaderExtensionCapability;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "RTCMacros.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
RTC_OBJC_EXPORT
|
||||
@interface RTC_OBJC_TYPE (RTCRtpHeaderExtensionCapability) : NSObject
|
||||
|
||||
/** The URI of the RTP header extension, as defined in RFC5285. */
|
||||
@property(nonatomic, readonly, copy) NSString *uri;
|
||||
|
||||
/** The value put in the RTP packet to identify the header extension. */
|
||||
@property(nonatomic, readonly, nullable) NSNumber* preferredId;
|
||||
|
||||
/** Whether the header extension is encrypted or not. */
|
||||
@property(nonatomic, readonly, getter=isPreferredEncrypted) BOOL preferredEncrypted;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
|
||||
#import "RTCRtpHeaderExtensionCapability+Private.h"
|
||||
|
||||
#import "helpers/NSString+StdString.h"
|
||||
|
||||
@implementation RTC_OBJC_TYPE (RTCRtpHeaderExtensionCapability)
|
||||
|
||||
@synthesize uri = _uri;
|
||||
@synthesize preferredId = _preferredId;
|
||||
@synthesize preferredEncrypted = _preferredEncrypted;
|
||||
|
||||
- (instancetype)init {
|
||||
webrtc::RtpHeaderExtensionCapability nativeRtpHeaderExtensionCapability;
|
||||
return [self initWithNativeRtpHeaderExtensionCapability:nativeRtpHeaderExtensionCapability];
|
||||
}
|
||||
|
||||
- (instancetype)initWithNativeRtpHeaderExtensionCapability:
|
||||
(const webrtc::RtpHeaderExtensionCapability &)nativeRtpHeaderExtensionCapability {
|
||||
if (self = [super init]) {
|
||||
_uri = [NSString stringForStdString:nativeRtpHeaderExtensionCapability.uri];
|
||||
if (nativeRtpHeaderExtensionCapability.preferred_id) {
|
||||
_preferredId = [NSNumber numberWithInt:*nativeRtpHeaderExtensionCapability.preferred_id];
|
||||
}
|
||||
_preferredEncrypted = nativeRtpHeaderExtensionCapability.preferred_encrypt;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"RTC_OBJC_TYPE(RTCRtpHeaderExtensionCapability) {\n uri: "
|
||||
@"%@\n preferredId: %@\n preferredEncrypted: %d\n}",
|
||||
_uri,
|
||||
_preferredId,
|
||||
_preferredEncrypted];
|
||||
}
|
||||
|
||||
- (webrtc::RtpHeaderExtensionCapability)nativeRtpHeaderExtensionCapability {
|
||||
webrtc::RtpHeaderExtensionCapability rtpHeaderExtensionCapability;
|
||||
rtpHeaderExtensionCapability.uri = [NSString stdStringForString:_uri];
|
||||
if (_preferredId != nil) {
|
||||
rtpHeaderExtensionCapability.preferred_id = absl::optional<int>(_preferredId.intValue);
|
||||
}
|
||||
rtpHeaderExtensionCapability.preferred_encrypt = _preferredEncrypted;
|
||||
return rtpHeaderExtensionCapability;
|
||||
}
|
||||
|
||||
@end
|
||||
@ -46,6 +46,7 @@ RTC_OBJC_EXPORT
|
||||
@end
|
||||
|
||||
@class RTC_OBJC_TYPE(RTCRtpTransceiver);
|
||||
@class RTC_OBJC_TYPE(RTCRtpCodecCapability);
|
||||
|
||||
/** The RTCRtpTransceiver maps to the RTCRtpTransceiver defined by the
|
||||
* WebRTC specification. A transceiver represents a combination of an RTCRtpSender
|
||||
@ -118,6 +119,12 @@ RTC_OBJC_EXPORT
|
||||
*/
|
||||
- (void)stopInternal;
|
||||
|
||||
/** The setCodecPreferences method overrides the default codec preferences used
|
||||
* by WebRTC for this transceiver.
|
||||
* https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-setcodecpreferences
|
||||
*/
|
||||
- (void)setCodecPreferences:(NSArray<RTC_OBJC_TYPE(RTCRtpCodecCapability) *> *)codecs;
|
||||
|
||||
/** An update of directionality does not take effect immediately. Instead,
|
||||
* future calls to createOffer and createAnswer mark the corresponding media
|
||||
* descriptions as sendrecv, sendonly, recvonly, or inactive.
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
|
||||
#import "RTCRtpTransceiver+Private.h"
|
||||
|
||||
#import "RTCRtpCodecCapability+Private.h"
|
||||
#import "RTCRtpEncodingParameters+Private.h"
|
||||
#import "RTCRtpParameters+Private.h"
|
||||
#import "RTCRtpReceiver+Private.h"
|
||||
@ -17,6 +18,8 @@
|
||||
#import "base/RTCLogging.h"
|
||||
#import "helpers/NSString+StdString.h"
|
||||
|
||||
#include "api/rtp_parameters.h"
|
||||
|
||||
NSString *const kRTCRtpTransceiverErrorDomain = @"org.webrtc.RTCRtpTranceiver";
|
||||
|
||||
@implementation RTC_OBJC_TYPE (RTCRtpTransceiverInit)
|
||||
@ -105,6 +108,14 @@ NSString *const kRTCRtpTransceiverErrorDomain = @"org.webrtc.RTCRtpTranceiver";
|
||||
_nativeRtpTransceiver->StopInternal();
|
||||
}
|
||||
|
||||
- (void)setCodecPreferences:(NSArray<RTC_OBJC_TYPE(RTCRtpCodecCapability) *> *)codecs {
|
||||
std::vector<webrtc::RtpCodecCapability> codecCapabilities;
|
||||
for (RTC_OBJC_TYPE(RTCRtpCodecCapability) * rtpCodecCapability in codecs) {
|
||||
codecCapabilities.push_back(rtpCodecCapability.nativeRtpCodecCapability);
|
||||
}
|
||||
_nativeRtpTransceiver->SetCodecPreferences(codecCapabilities);
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString
|
||||
stringWithFormat:@"RTC_OBJC_TYPE(RTCRtpTransceiver) {\n sender: %@\n receiver: %@\n}",
|
||||
|
||||
@ -8,6 +8,9 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import "base/RTCVideoDecoderFactory.h"
|
||||
#import "base/RTCVideoEncoderFactory.h"
|
||||
|
||||
#import "api/peerconnection/RTCAudioSource.h"
|
||||
#import "api/peerconnection/RTCConfiguration.h"
|
||||
#import "api/peerconnection/RTCDataChannel.h"
|
||||
@ -16,6 +19,8 @@
|
||||
#import "api/peerconnection/RTCMediaStreamTrack.h"
|
||||
#import "api/peerconnection/RTCPeerConnection.h"
|
||||
#import "api/peerconnection/RTCPeerConnectionFactory.h"
|
||||
#import "api/peerconnection/RTCRtpCapabilities.h"
|
||||
#import "api/peerconnection/RTCRtpCodecCapability.h"
|
||||
#import "api/peerconnection/RTCRtpReceiver.h"
|
||||
#import "api/peerconnection/RTCRtpSender.h"
|
||||
#import "api/peerconnection/RTCRtpTransceiver.h"
|
||||
@ -25,6 +30,40 @@
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
@interface MockVideoEncoderDecoderFactory
|
||||
: NSObject <RTC_OBJC_TYPE (RTCVideoEncoderFactory), RTC_OBJC_TYPE (RTCVideoDecoderFactory)>
|
||||
- (instancetype)initWithSupportedCodecs:
|
||||
(nonnull NSArray<RTC_OBJC_TYPE(RTCVideoCodecInfo) *> *)supportedCodecs;
|
||||
@end
|
||||
|
||||
@implementation MockVideoEncoderDecoderFactory {
|
||||
NSArray<RTC_OBJC_TYPE(RTCVideoCodecInfo) *> *_supportedCodecs;
|
||||
}
|
||||
|
||||
- (instancetype)initWithSupportedCodecs:
|
||||
(nonnull NSArray<RTC_OBJC_TYPE(RTCVideoCodecInfo) *> *)supportedCodecs {
|
||||
if (self = [super init]) {
|
||||
_supportedCodecs = supportedCodecs;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (nullable id<RTC_OBJC_TYPE(RTCVideoEncoder)>)createEncoder:
|
||||
(nonnull RTC_OBJC_TYPE(RTCVideoCodecInfo) *)info {
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (nullable id<RTC_OBJC_TYPE(RTCVideoDecoder)>)createDecoder:
|
||||
(nonnull RTC_OBJC_TYPE(RTCVideoCodecInfo) *)info {
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (nonnull NSArray<RTC_OBJC_TYPE(RTCVideoCodecInfo) *> *)supportedCodecs {
|
||||
return _supportedCodecs;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface RTCPeerConnectionFactoryTests : XCTestCase
|
||||
@end
|
||||
|
||||
@ -325,6 +364,147 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testSenderCapabilities {
|
||||
@autoreleasepool {
|
||||
RTC_OBJC_TYPE(RTCPeerConnectionFactory) * factory;
|
||||
MockVideoEncoderDecoderFactory *encoder;
|
||||
MockVideoEncoderDecoderFactory *decoder;
|
||||
|
||||
NSArray<RTC_OBJC_TYPE(RTCVideoCodecInfo) *> *supportedCodecs = @[
|
||||
[[RTC_OBJC_TYPE(RTCVideoCodecInfo) alloc] initWithName:@"VP8"],
|
||||
[[RTC_OBJC_TYPE(RTCVideoCodecInfo) alloc] initWithName:@"H264"]
|
||||
];
|
||||
|
||||
encoder = [[MockVideoEncoderDecoderFactory alloc] initWithSupportedCodecs:supportedCodecs];
|
||||
decoder = [[MockVideoEncoderDecoderFactory alloc] initWithSupportedCodecs:supportedCodecs];
|
||||
factory = [[RTC_OBJC_TYPE(RTCPeerConnectionFactory) alloc] initWithEncoderFactory:encoder
|
||||
decoderFactory:decoder];
|
||||
|
||||
RTC_OBJC_TYPE(RTCRtpCapabilities) *capabilities =
|
||||
[factory rtpSenderCapabilitiesForKind:kRTCMediaStreamTrackKindVideo];
|
||||
NSMutableArray<NSString *> *codecNames = [NSMutableArray new];
|
||||
for (RTC_OBJC_TYPE(RTCRtpCodecCapability) * codec in capabilities.codecs) {
|
||||
[codecNames addObject:codec.name];
|
||||
}
|
||||
|
||||
XCTAssertTrue([codecNames containsObject:@"VP8"]);
|
||||
XCTAssertTrue([codecNames containsObject:@"H264"]);
|
||||
factory = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testReceiverCapabilities {
|
||||
@autoreleasepool {
|
||||
RTC_OBJC_TYPE(RTCPeerConnectionFactory) * factory;
|
||||
MockVideoEncoderDecoderFactory *encoder;
|
||||
MockVideoEncoderDecoderFactory *decoder;
|
||||
|
||||
NSArray<RTC_OBJC_TYPE(RTCVideoCodecInfo) *> *supportedCodecs = @[
|
||||
[[RTC_OBJC_TYPE(RTCVideoCodecInfo) alloc] initWithName:@"VP8"],
|
||||
[[RTC_OBJC_TYPE(RTCVideoCodecInfo) alloc] initWithName:@"H264"]
|
||||
];
|
||||
|
||||
encoder = [[MockVideoEncoderDecoderFactory alloc] initWithSupportedCodecs:supportedCodecs];
|
||||
decoder = [[MockVideoEncoderDecoderFactory alloc] initWithSupportedCodecs:supportedCodecs];
|
||||
factory = [[RTC_OBJC_TYPE(RTCPeerConnectionFactory) alloc] initWithEncoderFactory:encoder
|
||||
decoderFactory:decoder];
|
||||
|
||||
RTC_OBJC_TYPE(RTCRtpCapabilities) *capabilities =
|
||||
[factory rtpReceiverCapabilitiesForKind:kRTCMediaStreamTrackKindVideo];
|
||||
NSMutableArray<NSString *> *codecNames = [NSMutableArray new];
|
||||
for (RTC_OBJC_TYPE(RTCRtpCodecCapability) * codec in capabilities.codecs) {
|
||||
[codecNames addObject:codec.name];
|
||||
}
|
||||
|
||||
XCTAssertTrue([codecNames containsObject:@"VP8"]);
|
||||
XCTAssertTrue([codecNames containsObject:@"H264"]);
|
||||
factory = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testSetCodecPreferences {
|
||||
@autoreleasepool {
|
||||
RTC_OBJC_TYPE(RTCConfiguration) *config = [[RTC_OBJC_TYPE(RTCConfiguration) alloc] init];
|
||||
RTC_OBJC_TYPE(RTCMediaConstraints) *constraints =
|
||||
[[RTC_OBJC_TYPE(RTCMediaConstraints) alloc] initWithMandatoryConstraints:nil
|
||||
optionalConstraints:nil];
|
||||
RTC_OBJC_TYPE(RTCRtpTransceiverInit) *init =
|
||||
[[RTC_OBJC_TYPE(RTCRtpTransceiverInit) alloc] init];
|
||||
|
||||
NSArray<RTC_OBJC_TYPE(RTCVideoCodecInfo) *> *supportedCodecs = @[
|
||||
[[RTC_OBJC_TYPE(RTCVideoCodecInfo) alloc] initWithName:@"VP8"],
|
||||
[[RTC_OBJC_TYPE(RTCVideoCodecInfo) alloc] initWithName:@"H264"]
|
||||
];
|
||||
|
||||
MockVideoEncoderDecoderFactory *encoder =
|
||||
[[MockVideoEncoderDecoderFactory alloc] initWithSupportedCodecs:supportedCodecs];
|
||||
MockVideoEncoderDecoderFactory *decoder =
|
||||
[[MockVideoEncoderDecoderFactory alloc] initWithSupportedCodecs:supportedCodecs];
|
||||
|
||||
RTC_OBJC_TYPE(RTCPeerConnectionFactory) * factory;
|
||||
RTC_OBJC_TYPE(RTCPeerConnection) * peerConnection;
|
||||
RTC_OBJC_TYPE(RTCRtpTransceiver) * tranceiver;
|
||||
factory = [[RTC_OBJC_TYPE(RTCPeerConnectionFactory) alloc] initWithEncoderFactory:encoder
|
||||
decoderFactory:decoder];
|
||||
|
||||
peerConnection = [factory peerConnectionWithConfiguration:config
|
||||
constraints:constraints
|
||||
delegate:nil];
|
||||
tranceiver = [peerConnection addTransceiverOfType:RTCRtpMediaTypeVideo init:init];
|
||||
XCTAssertNotNil(tranceiver);
|
||||
|
||||
RTC_OBJC_TYPE(RTCRtpCapabilities) *capabilities =
|
||||
[factory rtpReceiverCapabilitiesForKind:kRTCMediaStreamTrackKindVideo];
|
||||
|
||||
RTC_OBJC_TYPE(RTCRtpCodecCapability) * targetCodec;
|
||||
for (RTC_OBJC_TYPE(RTCRtpCodecCapability) * codec in capabilities.codecs) {
|
||||
if ([codec.name isEqual:@"VP8"]) {
|
||||
targetCodec = codec;
|
||||
break;
|
||||
}
|
||||
}
|
||||
XCTAssertNotNil(targetCodec);
|
||||
|
||||
[tranceiver setCodecPreferences:@[ targetCodec ]];
|
||||
|
||||
@autoreleasepool {
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
|
||||
__block BOOL completed = NO;
|
||||
[peerConnection
|
||||
offerForConstraints:constraints
|
||||
completionHandler:^(RTCSessionDescription *_Nullable sdp, NSError *_Nullable error) {
|
||||
XCTAssertNil(error);
|
||||
XCTAssertNotNil(sdp);
|
||||
|
||||
NSArray<NSString *> *rtpMaps = [self rtpMapsFromSDP:sdp.sdp];
|
||||
XCTAssertEqual(1, rtpMaps.count);
|
||||
|
||||
XCTAssertNotNil(targetCodec.preferredPayloadType);
|
||||
XCTAssertNotNil(targetCodec.clockRate);
|
||||
|
||||
NSString *expected =
|
||||
[NSString stringWithFormat:@"a=rtpmap:%i VP8/%i",
|
||||
targetCodec.preferredPayloadType.intValue,
|
||||
targetCodec.clockRate.intValue];
|
||||
|
||||
XCTAssertTrue([expected isEqualToString:rtpMaps[0]]);
|
||||
|
||||
completed = YES;
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
}];
|
||||
|
||||
[peerConnection close];
|
||||
peerConnection = nil;
|
||||
factory = nil;
|
||||
tranceiver = nil;
|
||||
|
||||
dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 15.0 * NSEC_PER_SEC));
|
||||
XCTAssertTrue(completed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (bool)negotiatePeerConnection:(RTC_OBJC_TYPE(RTCPeerConnection) *)pc1
|
||||
withPeerConnection:(RTC_OBJC_TYPE(RTCPeerConnection) *)pc2
|
||||
negotiationTimeout:(NSTimeInterval)timeout {
|
||||
@ -377,4 +557,16 @@
|
||||
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC)));
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)rtpMapsFromSDP:(NSString *)sdp {
|
||||
NSMutableArray<NSString *> *rtpMaps = [NSMutableArray new];
|
||||
NSArray *sdpLines =
|
||||
[sdp componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
|
||||
for (NSString *line in sdpLines) {
|
||||
if ([line hasPrefix:@"a=rtpmap"]) {
|
||||
[rtpMaps addObject:line];
|
||||
}
|
||||
}
|
||||
return rtpMaps;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user