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:
magjed
2016-11-22 07:46:03 -08:00
committed by Commit bot
parent 8271d04009
commit e60f020456
2 changed files with 96 additions and 47 deletions

View File

@ -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];

View File

@ -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];
}
}