iOS AppRTCMobile: Fix SDP video codec reordering for multiple H264 profiles
BUG=webrtc:6738 Review-Url: https://codereview.webrtc.org/2520933002 Cr-Commit-Position: refs/heads/master@{#15198}
This commit is contained in:
@ -26,8 +26,21 @@
|
||||
NSMutableArray *lines =
|
||||
[NSMutableArray arrayWithArray:
|
||||
[sdpString componentsSeparatedByString:lineSeparator]];
|
||||
// Find the line starting with "m=video".
|
||||
NSInteger mLineIndex = -1;
|
||||
NSString *codecRtpMap = nil;
|
||||
for (NSInteger i = 0; i < lines.count; ++i) {
|
||||
if ([lines[i] hasPrefix:@"m=video"]) {
|
||||
mLineIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mLineIndex == -1) {
|
||||
RTCLog(@"No m=video line, so can't prefer %@", codec);
|
||||
return description;
|
||||
}
|
||||
// An array with all payload types with name |codec|. The payload types are
|
||||
// integers in the range 96-127, but they are stored as strings here.
|
||||
NSMutableArray *codecPayloadTypes = [[NSMutableArray alloc] init];
|
||||
// a=rtpmap:<payload type> <encoding name>/<clock rate>
|
||||
// [/<encoding parameters>]
|
||||
NSString *pattern =
|
||||
@ -36,54 +49,47 @@
|
||||
[NSRegularExpression regularExpressionWithPattern:pattern
|
||||
options:0
|
||||
error:nil];
|
||||
for (NSInteger i = 0; (i < lines.count) && (mLineIndex == -1 || !codecRtpMap);
|
||||
++i) {
|
||||
NSString *line = lines[i];
|
||||
if ([line hasPrefix:@"m=video"]) {
|
||||
mLineIndex = i;
|
||||
continue;
|
||||
}
|
||||
for (NSString *line in lines) {
|
||||
NSTextCheckingResult *codecMatches =
|
||||
[regex firstMatchInString:line
|
||||
options:0
|
||||
range:NSMakeRange(0, line.length)];
|
||||
if (codecMatches) {
|
||||
codecRtpMap =
|
||||
[line substringWithRange:[codecMatches rangeAtIndex:1]];
|
||||
continue;
|
||||
[codecPayloadTypes
|
||||
addObject:[line substringWithRange:[codecMatches rangeAtIndex:1]]];
|
||||
}
|
||||
}
|
||||
if (mLineIndex == -1) {
|
||||
RTCLog(@"No m=video line, so can't prefer %@", codec);
|
||||
return description;
|
||||
}
|
||||
if (!codecRtpMap) {
|
||||
RTCLog(@"No rtpmap for %@", codec);
|
||||
if ([codecPayloadTypes count] == 0) {
|
||||
RTCLog(@"No payload types with name %@", codec);
|
||||
return description;
|
||||
}
|
||||
NSArray *origMLineParts =
|
||||
[lines[mLineIndex] componentsSeparatedByString:mLineSeparator];
|
||||
if (origMLineParts.count > 3) {
|
||||
NSMutableArray *newMLineParts =
|
||||
[NSMutableArray arrayWithCapacity:origMLineParts.count];
|
||||
NSInteger origPartIndex = 0;
|
||||
// Format is: m=<media> <port> <proto> <fmt> ...
|
||||
[newMLineParts addObject:origMLineParts[origPartIndex++]];
|
||||
[newMLineParts addObject:origMLineParts[origPartIndex++]];
|
||||
[newMLineParts addObject:origMLineParts[origPartIndex++]];
|
||||
[newMLineParts addObject:codecRtpMap];
|
||||
for (; origPartIndex < origMLineParts.count; ++origPartIndex) {
|
||||
if (![codecRtpMap isEqualToString:origMLineParts[origPartIndex]]) {
|
||||
[newMLineParts addObject:origMLineParts[origPartIndex]];
|
||||
}
|
||||
}
|
||||
NSString *newMLine =
|
||||
[newMLineParts componentsJoinedByString:mLineSeparator];
|
||||
[lines replaceObjectAtIndex:mLineIndex
|
||||
withObject:newMLine];
|
||||
} else {
|
||||
// The format of ML should be: m=<media> <port> <proto> <fmt> ...
|
||||
const int kHeaderLength = 3;
|
||||
if (origMLineParts.count <= kHeaderLength) {
|
||||
RTCLogWarning(@"Wrong SDP media description format: %@", lines[mLineIndex]);
|
||||
return description;
|
||||
}
|
||||
// Split the line into header and payloadTypes.
|
||||
NSRange headerRange = NSMakeRange(0, kHeaderLength);
|
||||
NSRange payloadRange =
|
||||
NSMakeRange(kHeaderLength, origMLineParts.count - kHeaderLength);
|
||||
NSArray *header = [origMLineParts subarrayWithRange:headerRange];
|
||||
NSMutableArray *payloadTypes = [NSMutableArray
|
||||
arrayWithArray:[origMLineParts subarrayWithRange:payloadRange]];
|
||||
// Reconstruct the line with |codecPayloadTypes| moved to the beginning of the
|
||||
// payload types.
|
||||
NSMutableArray *newMLineParts = [NSMutableArray arrayWithCapacity:origMLineParts.count];
|
||||
[newMLineParts addObjectsFromArray:header];
|
||||
[newMLineParts addObjectsFromArray:codecPayloadTypes];
|
||||
[payloadTypes removeObjectsInArray:codecPayloadTypes];
|
||||
[newMLineParts addObjectsFromArray:payloadTypes];
|
||||
|
||||
NSString *newMLine = [newMLineParts componentsJoinedByString:mLineSeparator];
|
||||
[lines replaceObjectAtIndex:mLineIndex
|
||||
withObject:newMLine];
|
||||
|
||||
NSString *mangledSdpString = [lines componentsJoinedByString:lineSeparator];
|
||||
return [[RTCSessionDescription alloc] initWithType:description.type
|
||||
sdp:mangledSdpString];
|
||||
|
||||
@ -354,22 +354,23 @@ static NSInteger kARDAppClientTestsExpectationTimeoutError = 100;
|
||||
@end
|
||||
|
||||
@interface ARDSDPUtilsTest : ARDTestCase
|
||||
- (void)testPreferVideoCodec;
|
||||
- (void)testPreferVideoCodec:(NSString *)codec
|
||||
sdp:(NSString *)sdp
|
||||
expectedSdp:(NSString *)expectedSdp;
|
||||
@end
|
||||
|
||||
@implementation ARDSDPUtilsTest
|
||||
|
||||
- (void)testPreferVideoCodec {
|
||||
NSString *sdp = @("m=video 9 RTP/SAVPF 100 116 117 96 120\n"
|
||||
"a=rtpmap:120 H264/90000\n");
|
||||
NSString *expectedSdp = @("m=video 9 RTP/SAVPF 120 100 116 117 96\n"
|
||||
"a=rtpmap:120 H264/90000\n");
|
||||
- (void)testPreferVideoCodec:(NSString *)codec
|
||||
sdp:(NSString *)sdp
|
||||
expectedSdp:(NSString *)expectedSdp {
|
||||
RTCSessionDescription* desc =
|
||||
[[RTCSessionDescription alloc] initWithType:RTCSdpTypeOffer sdp:sdp];
|
||||
RTCSessionDescription *h264Desc =
|
||||
RTCSessionDescription *outputDesc =
|
||||
[ARDSDPUtils descriptionForDescription:desc
|
||||
preferredVideoCodec:@"H264"];
|
||||
EXPECT_TRUE([h264Desc.description rangeOfString:expectedSdp].location != NSNotFound);
|
||||
preferredVideoCodec:codec];
|
||||
EXPECT_TRUE([outputDesc.description rangeOfString:expectedSdp].location !=
|
||||
NSNotFound);
|
||||
}
|
||||
|
||||
@end
|
||||
@ -401,10 +402,52 @@ TEST_F(SignalingTest, SessionLocalVideoCallbackTest) {
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_F(SignalingTest, SDPTest) {
|
||||
TEST_F(SignalingTest, SdpH264Test) {
|
||||
@autoreleasepool {
|
||||
ARDSDPUtilsTest *test = [[ARDSDPUtilsTest alloc] init];
|
||||
[test testPreferVideoCodec];
|
||||
NSString *sdp = @("m=video 9 RTP/SAVPF 100 116 117 96 120 97\n"
|
||||
"a=rtpmap:120 H264/90000\n"
|
||||
"a=rtpmap:97 H264/90000\n");
|
||||
NSString *expectedSdp = @("m=video 9 RTP/SAVPF 120 97 100 116 117 96\n"
|
||||
"a=rtpmap:120 H264/90000\n"
|
||||
"a=rtpmap:97 H264/90000\n");
|
||||
[test testPreferVideoCodec:@"H264"
|
||||
sdp:sdp
|
||||
expectedSdp:expectedSdp];
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(SignalingTest, SdpVp8Test) {
|
||||
@autoreleasepool {
|
||||
ARDSDPUtilsTest *test = [[ARDSDPUtilsTest alloc] init];
|
||||
NSString *sdp = @("m=video 9 RTP/SAVPF 100 116 117 96 120 97\n"
|
||||
"a=rtpmap:116 VP8/90000\n");
|
||||
NSString *expectedSdp = @("m=video 9 RTP/SAVPF 116 100 117 96 120 97\n"
|
||||
"a=rtpmap:116 VP8/90000\n");
|
||||
[test testPreferVideoCodec:@"VP8"
|
||||
sdp:sdp
|
||||
expectedSdp:expectedSdp];
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(SignalingTest, SdpNoMLineTest) {
|
||||
@autoreleasepool {
|
||||
ARDSDPUtilsTest *test = [[ARDSDPUtilsTest alloc] init];
|
||||
NSString *sdp = @("a=rtpmap:116 VP8/90000\n");
|
||||
[test testPreferVideoCodec:@"VP8"
|
||||
sdp:sdp
|
||||
expectedSdp:sdp];
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(SignalingTest, SdpMissingCodecTest) {
|
||||
@autoreleasepool {
|
||||
ARDSDPUtilsTest *test = [[ARDSDPUtilsTest alloc] init];
|
||||
NSString *sdp = @("m=video 9 RTP/SAVPF 100 116 117 96 120 97\n"
|
||||
"a=rtpmap:116 VP8/90000\n");
|
||||
[test testPreferVideoCodec:@"foo"
|
||||
sdp:sdp
|
||||
expectedSdp:sdp];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user