diff --git a/webrtc/examples/objc/AppRTCMobile/ARDSDPUtils.m b/webrtc/examples/objc/AppRTCMobile/ARDSDPUtils.m index 3a8a578dc6..016829eeec 100644 --- a/webrtc/examples/objc/AppRTCMobile/ARDSDPUtils.m +++ b/webrtc/examples/objc/AppRTCMobile/ARDSDPUtils.m @@ -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: / // [/] 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= ... - [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= ... + 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]; diff --git a/webrtc/examples/objc/AppRTCMobile/tests/ARDAppClientTest.mm b/webrtc/examples/objc/AppRTCMobile/tests/ARDAppClientTest.mm index 20a5cf481e..b206925420 100644 --- a/webrtc/examples/objc/AppRTCMobile/tests/ARDAppClientTest.mm +++ b/webrtc/examples/objc/AppRTCMobile/tests/ARDAppClientTest.mm @@ -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]; } }