AppRTCDemo(iOS): prefer ISAC as audio codec
This makes audio flow well bidirectionally to an iPod Touch (5th gen).
Also:
- Update to new turnserver JSON style:
- separate username field
- multiple URLs for the same server (e.g. both UDP & TCP)
- Added more explicit logging for ICE Connected since it's useful for debugging
- Give focus to the input field on app launch since that's the only useful
thing to have focus on, anyway.
- Fix minor typos
- Cleaned up trailing whitespace and hard tabs
BUG=2191
R=wu@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/2127004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@4687 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/talk/examples/ios/AppRTCDemo/APPRTCAppDelegate.m b/talk/examples/ios/AppRTCDemo/APPRTCAppDelegate.m
index 710f4ad..34aa752 100644
--- a/talk/examples/ios/AppRTCDemo/APPRTCAppDelegate.m
+++ b/talk/examples/ios/AppRTCDemo/APPRTCAppDelegate.m
@@ -62,7 +62,7 @@
- (void)peerConnection:(RTCPeerConnection *)peerConnection
signalingStateChanged:(RTCSignalingState)stateChanged {
- NSLog(@"PCO onSignalingStateChange.");
+ NSLog(@"PCO onSignalingStateChange: %d", stateChanged);
}
- (void)peerConnection:(RTCPeerConnection *)peerConnection
@@ -119,6 +119,13 @@
- (void)peerConnection:(RTCPeerConnection *)peerConnection
iceConnectionChanged:(RTCICEConnectionState)newState {
NSLog(@"PCO onIceConnectionChange. %d", newState);
+ if (newState == RTCICEConnectionConnected)
+ [self displayLogMessage:@"ICE Connection Connected."];
+ NSAssert(newState != RTCICEConnectionFailed, @"ICE Connection failed!");
+}
+
+- (void)displayLogMessage:(NSString *)message {
+ [_delegate displayLogMessage:message];
}
@end
@@ -258,8 +265,8 @@
} else if (([value compare:@"offer"] == NSOrderedSame) ||
([value compare:@"answer"] == NSOrderedSame)) {
NSString *sdpString = [objects objectForKey:@"sdp"];
- RTCSessionDescription *sdp =
- [[RTCSessionDescription alloc] initWithType:value sdp:sdpString];
+ RTCSessionDescription *sdp = [[RTCSessionDescription alloc]
+ initWithType:value sdp:[APPRTCAppDelegate preferISAC:sdpString]];
[self.peerConnection setRemoteDescriptionWithDelegate:self
sessionDescription:sdp];
[self displayLogMessage:@"PC - setRemoteDescription."];
@@ -283,8 +290,71 @@
#pragma mark - RTCSessionDescriptonDelegate methods
+// Match |pattern| to |string| and return the first group of the first
+// match, or nil if no match was found.
++ (NSString *)firstMatch:(NSRegularExpression *)pattern
+ withString:(NSString *)string {
+ NSTextCheckingResult* result =
+ [pattern firstMatchInString:string
+ options:0
+ range:NSMakeRange(0, [string length])];
+ if (!result)
+ return nil;
+ return [string substringWithRange:[result rangeAtIndex:1]];
+}
+
+// Mangle |origSDP| to prefer the ISAC/16k audio codec.
++ (NSString *)preferISAC:(NSString *)origSDP {
+ int mLineIndex = -1;
+ NSString* isac16kRtpMap = nil;
+ NSArray* lines = [origSDP componentsSeparatedByString:@"\n"];
+ NSRegularExpression* isac16kRegex = [NSRegularExpression
+ regularExpressionWithPattern:@"^a=rtpmap:(\\d+) ISAC/16000[\r]?$"
+ options:0
+ error:nil];
+ for (int i = 0;
+ (i < [lines count]) && (mLineIndex == -1 || isac16kRtpMap == nil);
+ ++i) {
+ NSString* line = [lines objectAtIndex:i];
+ if ([line hasPrefix:@"m=audio "]) {
+ mLineIndex = i;
+ continue;
+ }
+ isac16kRtpMap = [self firstMatch:isac16kRegex withString:line];
+ }
+ if (mLineIndex == -1) {
+ NSLog(@"No m=audio line, so can't prefer iSAC");
+ return origSDP;
+ }
+ if (isac16kRtpMap == nil) {
+ NSLog(@"No ISAC/16000 line, so can't prefer iSAC");
+ return origSDP;
+ }
+ NSArray* origMLineParts =
+ [[lines objectAtIndex:mLineIndex] componentsSeparatedByString:@" "];
+ NSMutableArray* newMLine =
+ [NSMutableArray arrayWithCapacity:[origMLineParts count]];
+ int origPartIndex = 0;
+ // Format is: m=<media> <port> <proto> <fmt> ...
+ [newMLine addObject:[origMLineParts objectAtIndex:origPartIndex++]];
+ [newMLine addObject:[origMLineParts objectAtIndex:origPartIndex++]];
+ [newMLine addObject:[origMLineParts objectAtIndex:origPartIndex++]];
+ [newMLine addObject:isac16kRtpMap];
+ for (; origPartIndex < [origMLineParts count]; ++origPartIndex) {
+ if ([isac16kRtpMap compare:[origMLineParts objectAtIndex:origPartIndex]]
+ != NSOrderedSame) {
+ [newMLine addObject:[origMLineParts objectAtIndex:origPartIndex]];
+ }
+ }
+ NSMutableArray* newLines = [NSMutableArray arrayWithCapacity:[lines count]];
+ [newLines addObjectsFromArray:lines];
+ [newLines replaceObjectAtIndex:mLineIndex
+ withObject:[newMLine componentsJoinedByString:@" "]];
+ return [newLines componentsJoinedByString:@"\n"];
+}
+
- (void)peerConnection:(RTCPeerConnection *)peerConnection
- didCreateSessionDescription:(RTCSessionDescription *)sdp
+ didCreateSessionDescription:(RTCSessionDescription *)origSdp
error:(NSError *)error {
if (error) {
[self displayLogMessage:@"SDP onFailure."];
@@ -293,6 +363,10 @@
}
[self displayLogMessage:@"SDP onSuccess(SDP) - set local description."];
+ RTCSessionDescription* sdp =
+ [[RTCSessionDescription alloc]
+ initWithType:origSdp.type
+ sdp:[APPRTCAppDelegate preferISAC:origSdp.description]];
[self.peerConnection setLocalDescriptionWithDelegate:self
sessionDescription:sdp];
[self displayLogMessage:@"PC setLocalDescription."];