diff options
author | fischman@webrtc.org <fischman@webrtc.org@4adac7df-926f-26a2-2b94-8c16560cd09d> | 2014-03-25 00:11:56 +0000 |
---|---|---|
committer | fischman@webrtc.org <fischman@webrtc.org@4adac7df-926f-26a2-2b94-8c16560cd09d> | 2014-03-25 00:11:56 +0000 |
commit | bb288156332dd2e684f0dde156bd984c73da210b (patch) | |
tree | 55ae6782c50283b3ae7ae440ce4b43c55ce3c9fe /examples | |
parent | 333c9e9a22496185b7986a9b6c998ab162e3dc57 (diff) | |
download | talk-bb288156332dd2e684f0dde156bd984c73da210b.tar.gz |
AppRTCDemo(ios): style/cleanup fixes following cr/62871616-p10
BUG=2168
R=noahric@google.com
Review URL: https://webrtc-codereview.appspot.com/9709004
git-svn-id: http://webrtc.googlecode.com/svn/trunk/talk@5768 4adac7df-926f-26a2-2b94-8c16560cd09d
Diffstat (limited to 'examples')
-rw-r--r-- | examples/ios/AppRTCDemo/APPRTCAppClient.h | 18 | ||||
-rw-r--r-- | examples/ios/AppRTCDemo/APPRTCAppClient.m | 282 | ||||
-rw-r--r-- | examples/ios/AppRTCDemo/APPRTCAppDelegate.h | 8 | ||||
-rw-r--r-- | examples/ios/AppRTCDemo/APPRTCAppDelegate.m | 351 | ||||
-rw-r--r-- | examples/ios/AppRTCDemo/APPRTCVideoView.h (renamed from examples/ios/AppRTCDemo/VideoView.h) | 9 | ||||
-rw-r--r-- | examples/ios/AppRTCDemo/APPRTCVideoView.m | 82 | ||||
-rw-r--r-- | examples/ios/AppRTCDemo/APPRTCViewController.h | 14 | ||||
-rw-r--r-- | examples/ios/AppRTCDemo/APPRTCViewController.m | 148 | ||||
-rw-r--r-- | examples/ios/AppRTCDemo/GAEChannelClient.m | 58 | ||||
-rw-r--r-- | examples/ios/AppRTCDemo/VideoView.m | 168 | ||||
-rw-r--r-- | examples/ios/AppRTCDemo/main.m | 2 |
11 files changed, 509 insertions, 631 deletions
diff --git a/examples/ios/AppRTCDemo/APPRTCAppClient.h b/examples/ios/AppRTCDemo/APPRTCAppClient.h index 410ead6..41a795e 100644 --- a/examples/ios/AppRTCDemo/APPRTCAppClient.h +++ b/examples/ios/AppRTCDemo/APPRTCAppClient.h @@ -47,12 +47,20 @@ // for the registered handler to be called with received messages. @interface APPRTCAppClient : NSObject<NSURLConnectionDataDelegate> -@property(nonatomic, assign) id<ICEServerDelegate> ICEServerDelegate; -@property(nonatomic, assign) id<GAEMessageHandler> messageHandler; +@property(nonatomic, weak, readonly) id<ICEServerDelegate> ICEServerDelegate; +@property(nonatomic, weak, readonly) id<GAEMessageHandler> messageHandler; @property(nonatomic, assign) BOOL initiator; -@property(nonatomic, strong) RTCMediaConstraints* videoConstraints; +@property(nonatomic, copy, readonly) RTCMediaConstraints* videoConstraints; -- (void)connectToRoom:(NSURL *)room; -- (void)sendData:(NSData *)data; +- (id)initWithICEServerDelegate:(id<ICEServerDelegate>)delegate + messageHandler:(id<GAEMessageHandler>)handler; +- (void)connectToRoom:(NSURL*)room; +- (void)sendData:(NSData*)data; + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +// Disallow init and don't add to documentation +- (id)init __attribute__(( + unavailable("init is not a supported initializer for this class."))); +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ @end diff --git a/examples/ios/AppRTCDemo/APPRTCAppClient.m b/examples/ios/AppRTCDemo/APPRTCAppClient.m index 5b035e3..9ac83ff 100644 --- a/examples/ios/AppRTCDemo/APPRTCAppClient.m +++ b/examples/ios/AppRTCDemo/APPRTCAppClient.m @@ -37,13 +37,13 @@ @interface APPRTCAppClient () @property(nonatomic, strong) dispatch_queue_t backgroundQueue; -@property(nonatomic, copy) NSString *baseURL; -@property(nonatomic, strong) GAEChannelClient *gaeChannel; -@property(nonatomic, copy) NSString *postMessageUrl; -@property(nonatomic, copy) NSString *pcConfig; -@property(nonatomic, strong) NSMutableString *roomHtml; -@property(atomic, strong) NSMutableArray *sendQueue; -@property(nonatomic, copy) NSString *token; +@property(nonatomic, copy) NSString* baseURL; +@property(nonatomic, strong) GAEChannelClient* gaeChannel; +@property(nonatomic, copy) NSString* postMessageUrl; +@property(nonatomic, copy) NSString* pcConfig; +@property(nonatomic, strong) NSMutableString* roomHtml; +@property(atomic, strong) NSMutableArray* sendQueue; +@property(nonatomic, copy) NSString* token; @property(nonatomic, assign) BOOL verboseLogging; @@ -51,23 +51,11 @@ @implementation APPRTCAppClient -@synthesize ICEServerDelegate = _ICEServerDelegate; -@synthesize messageHandler = _messageHandler; - -@synthesize backgroundQueue = _backgroundQueue; -@synthesize baseURL = _baseURL; -@synthesize gaeChannel = _gaeChannel; -@synthesize postMessageUrl = _postMessageUrl; -@synthesize pcConfig = _pcConfig; -@synthesize roomHtml = _roomHtml; -@synthesize sendQueue = _sendQueue; -@synthesize token = _token; -@synthesize verboseLogging = _verboseLogging; -@synthesize initiator = _initiator; -@synthesize videoConstraints = _videoConstraints; - -- (id)init { +- (id)initWithICEServerDelegate:(id<ICEServerDelegate>)delegate + messageHandler:(id<GAEMessageHandler>)handler { if (self = [super init]) { + _ICEServerDelegate = delegate; + _messageHandler = handler; _backgroundQueue = dispatch_queue_create("RTCBackgroundQueue", NULL); _sendQueue = [NSMutableArray array]; // Uncomment to see Request/Response logging. @@ -78,12 +66,12 @@ #pragma mark - Public methods -- (void)connectToRoom:(NSURL *)url { - NSURLRequest *request = [self getRequestFromUrl:url]; +- (void)connectToRoom:(NSURL*)url { + NSURLRequest* request = [self getRequestFromUrl:url]; [NSURLConnection connectionWithRequest:request delegate:self]; } -- (void)sendData:(NSData *)data { +- (void)sendData:(NSData*)data { @synchronized(self) { [self maybeLogMessage:@"Send message"]; [self.sendQueue addObject:[data copy]]; @@ -93,49 +81,53 @@ #pragma mark - Internal methods -- (NSString*)findVar:(NSString*)name - strippingQuotes:(BOOL)strippingQuotes { +- (NSString*)findVar:(NSString*)name strippingQuotes:(BOOL)strippingQuotes { NSError* error; NSString* pattern = [NSString stringWithFormat:@".*\n *var %@ = ([^\n]*);\n.*", name]; - NSRegularExpression *regexp = + NSRegularExpression* regexp = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:&error]; - NSAssert(!error, @"Unexpected error compiling regex: ", + NSAssert(!error, + @"Unexpected error compiling regex: ", error.localizedDescription); NSRange fullRange = NSMakeRange(0, [self.roomHtml length]); - NSArray *matches = + NSArray* matches = [regexp matchesInString:self.roomHtml options:0 range:fullRange]; if ([matches count] != 1) { [self showMessage:[NSString stringWithFormat:@"%d matches for %@ in %@", - [matches count], name, self.roomHtml]]; + [matches count], + name, + self.roomHtml]]; return nil; } NSRange matchRange = [matches[0] rangeAtIndex:1]; NSString* value = [self.roomHtml substringWithRange:matchRange]; if (strippingQuotes) { NSAssert([value length] > 2, - @"Can't strip quotes from short string: [%@]", value); + @"Can't strip quotes from short string: [%@]", + value); NSAssert(([value characterAtIndex:0] == '\'' && [value characterAtIndex:[value length] - 1] == '\''), - @"Can't strip quotes from unquoted string: [%@]", value); + @"Can't strip quotes from unquoted string: [%@]", + value); value = [value substringWithRange:NSMakeRange(1, [value length] - 2)]; } return value; } -- (NSURLRequest *)getRequestFromUrl:(NSURL *)url { +- (NSURLRequest*)getRequestFromUrl:(NSURL*)url { self.roomHtml = [NSMutableString stringWithCapacity:20000]; - NSString *path = + NSString* path = [NSString stringWithFormat:@"https:%@", [url resourceSpecifier]]; - NSURLRequest *request = + NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:path]]; return request; } -- (void)maybeLogMessage:(NSString *)message { +- (void)maybeLogMessage:(NSString*)message { if (self.verboseLogging) { NSLog(@"%@", message); } @@ -143,33 +135,33 @@ - (void)requestQueueDrainInBackground { dispatch_async(self.backgroundQueue, ^(void) { - // TODO(hughv): This can block the UI thread. Fix. - @synchronized(self) { - if ([self.postMessageUrl length] < 1) { - return; + // TODO(hughv): This can block the UI thread. Fix. + @synchronized(self) { + if ([self.postMessageUrl length] < 1) { + return; + } + for (NSData* data in self.sendQueue) { + NSString* url = + [NSString stringWithFormat:@"%@/%@", + self.baseURL, self.postMessageUrl]; + [self sendData:data withUrl:url]; + } + [self.sendQueue removeAllObjects]; } - for (NSData *data in self.sendQueue) { - NSString *url = [NSString stringWithFormat:@"%@/%@", - self.baseURL, - self.postMessageUrl]; - [self sendData:data withUrl:url]; - } - [self.sendQueue removeAllObjects]; - } - }); + }); } -- (void)sendData:(NSData *)data withUrl:(NSString *)url { - NSMutableURLRequest *request = +- (void)sendData:(NSData*)data withUrl:(NSString*)url { + NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]]; request.HTTPMethod = @"POST"; [request setHTTPBody:data]; - NSURLResponse *response; - NSError *error; - NSData *responseData = [NSURLConnection sendSynchronousRequest:request + NSURLResponse* response; + NSError* error; + NSData* responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; - NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; + NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response; int status = [httpResponse statusCode]; NSAssert(status == 200, @"Bad response [%d] to message: %@\n\n%@", @@ -178,9 +170,9 @@ [NSString stringWithUTF8String:[responseData bytes]]); } -- (void)showMessage:(NSString *)message { +- (void)showMessage:(NSString*)message { NSLog(@"%@", message); - UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Unable to join" + UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:@"Unable to join" message:message delegate:nil cancelButtonTitle:@"OK" @@ -188,96 +180,97 @@ [alertView show]; } -- (void)updateICEServers:(NSMutableArray *)ICEServers - withTurnServer:(NSString *)turnServerUrl { +- (void)updateICEServers:(NSMutableArray*)ICEServers + withTurnServer:(NSString*)turnServerUrl { if ([turnServerUrl length] < 1) { [self.ICEServerDelegate onICEServers:ICEServers]; return; } dispatch_async(self.backgroundQueue, ^(void) { - NSMutableURLRequest *request = [NSMutableURLRequest - requestWithURL:[NSURL URLWithString:turnServerUrl]]; - [request addValue:@"Mozilla/5.0" forHTTPHeaderField:@"user-agent"]; - [request addValue:@"https://apprtc.appspot.com" - forHTTPHeaderField:@"origin"]; - NSURLResponse *response; - NSError *error; - NSData *responseData = [NSURLConnection sendSynchronousRequest:request - returningResponse:&response - error:&error]; - if (!error) { - NSDictionary *json = [NSJSONSerialization JSONObjectWithData:responseData - options:0 - error:&error]; - NSAssert(!error, @"Unable to parse. %@", error.localizedDescription); - NSString *username = json[@"username"]; - NSString *password = json[@"password"]; - NSArray* uris = json[@"uris"]; - for (int i = 0; i < [uris count]; ++i) { - NSString *turnServer = [uris objectAtIndex:i]; - RTCICEServer *ICEServer = - [[RTCICEServer alloc] initWithURI:[NSURL URLWithString:turnServer] - username:username - password:password]; - NSLog(@"Added ICE Server: %@", ICEServer); - [ICEServers addObject:ICEServer]; + NSMutableURLRequest* request = [NSMutableURLRequest + requestWithURL:[NSURL URLWithString:turnServerUrl]]; + [request addValue:@"Mozilla/5.0" forHTTPHeaderField:@"user-agent"]; + [request addValue:@"https://apprtc.appspot.com" + forHTTPHeaderField:@"origin"]; + NSURLResponse* response; + NSError* error; + NSData* responseData = [NSURLConnection sendSynchronousRequest:request + returningResponse:&response + error:&error]; + if (!error) { + NSDictionary* json = + [NSJSONSerialization JSONObjectWithData:responseData + options:0 + error:&error]; + NSAssert(!error, @"Unable to parse. %@", error.localizedDescription); + NSString* username = json[@"username"]; + NSString* password = json[@"password"]; + NSArray* uris = json[@"uris"]; + for (int i = 0; i < [uris count]; ++i) { + NSString* turnServer = [uris objectAtIndex:i]; + RTCICEServer* ICEServer = + [[RTCICEServer alloc] initWithURI:[NSURL URLWithString:turnServer] + username:username + password:password]; + NSLog(@"Added ICE Server: %@", ICEServer); + [ICEServers addObject:ICEServer]; + } + } else { + NSLog(@"Unable to get TURN server. Error: %@", error.description); } - } else { - NSLog(@"Unable to get TURN server. Error: %@", error.description); - } - dispatch_async(dispatch_get_main_queue(), ^(void) { - [self.ICEServerDelegate onICEServers:ICEServers]; - }); + dispatch_async(dispatch_get_main_queue(), ^(void) { + [self.ICEServerDelegate onICEServers:ICEServers]; + }); }); } #pragma mark - NSURLConnectionDataDelegate methods -- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { - NSString *roomHtml = [NSString stringWithUTF8String:[data bytes]]; - [self maybeLogMessage: - [NSString stringWithFormat:@"Received %d chars", [roomHtml length]]]; +- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data { + NSString* roomHtml = [NSString stringWithUTF8String:[data bytes]]; + [self maybeLogMessage:[NSString stringWithFormat:@"Received %d chars", + [roomHtml length]]]; [self.roomHtml appendString:roomHtml]; } -- (void)connection:(NSURLConnection *)connection - didReceiveResponse:(NSURLResponse *)response { - NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; +- (void)connection:(NSURLConnection*)connection + didReceiveResponse:(NSURLResponse*)response { + NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response; int statusCode = [httpResponse statusCode]; - [self maybeLogMessage: + [self + maybeLogMessage: [NSString stringWithFormat: - @"Response received\nURL\n%@\nStatus [%d]\nHeaders\n%@", - [httpResponse URL], - statusCode, - [httpResponse allHeaderFields]]]; + @"Response received\nURL\n%@\nStatus [%d]\nHeaders\n%@", + [httpResponse URL], + statusCode, + [httpResponse allHeaderFields]]]; NSAssert(statusCode == 200, @"Invalid response of %d received.", statusCode); } -- (void)connectionDidFinishLoading:(NSURLConnection *)connection { +- (void)connectionDidFinishLoading:(NSURLConnection*)connection { [self maybeLogMessage:[NSString stringWithFormat:@"finished loading %d chars", - [self.roomHtml length]]]; + [self.roomHtml length]]]; NSRegularExpression* fullRegex = - [NSRegularExpression regularExpressionWithPattern:@"room is full" - options:0 - error:nil]; + [NSRegularExpression regularExpressionWithPattern:@"room is full" + options:0 + error:nil]; if ([fullRegex numberOfMatchesInString:self.roomHtml options:0 range:NSMakeRange(0, [self.roomHtml length])]) { [self showMessage:@"Room full"]; - APPRTCAppDelegate *ad = - (APPRTCAppDelegate *)[[UIApplication sharedApplication] delegate]; + APPRTCAppDelegate* ad = + (APPRTCAppDelegate*)[[UIApplication sharedApplication] delegate]; [ad closeVideoUI]; return; } - - NSString *fullUrl = [[[connection originalRequest] URL] absoluteString]; + NSString* fullUrl = [[[connection originalRequest] URL] absoluteString]; NSRange queryRange = [fullUrl rangeOfString:@"?"]; self.baseURL = [fullUrl substringToIndex:queryRange.location]; - [self maybeLogMessage: - [NSString stringWithFormat:@"Base URL: %@", self.baseURL]]; + [self maybeLogMessage:[NSString + stringWithFormat:@"Base URL: %@", self.baseURL]]; self.initiator = [[self findVar:@"initiator" strippingQuotes:NO] boolValue]; self.token = [self findVar:@"channelToken" strippingQuotes:YES]; @@ -290,45 +283,45 @@ if (!roomKey || !me) return; self.postMessageUrl = - [NSString stringWithFormat:@"/message?r=%@&u=%@", roomKey, me]; + [NSString stringWithFormat:@"/message?r=%@&u=%@", roomKey, me]; [self maybeLogMessage:[NSString stringWithFormat:@"POST message URL: %@", - self.postMessageUrl]]; + self.postMessageUrl]]; NSString* pcConfig = [self findVar:@"pcConfig" strippingQuotes:NO]; if (!pcConfig) return; - [self maybeLogMessage: - [NSString stringWithFormat:@"PC Config JSON: %@", pcConfig]]; + [self maybeLogMessage:[NSString + stringWithFormat:@"PC Config JSON: %@", pcConfig]]; - NSString *turnServerUrl = [self findVar:@"turnUrl" strippingQuotes:YES]; + NSString* turnServerUrl = [self findVar:@"turnUrl" strippingQuotes:YES]; if (turnServerUrl) { - [self maybeLogMessage: - [NSString stringWithFormat:@"TURN server request URL: %@", - turnServerUrl]]; + [self maybeLogMessage:[NSString + stringWithFormat:@"TURN server request URL: %@", + turnServerUrl]]; } - NSError *error; - NSData *pcData = [pcConfig dataUsingEncoding:NSUTF8StringEncoding]; - NSDictionary *json = + NSError* error; + NSData* pcData = [pcConfig dataUsingEncoding:NSUTF8StringEncoding]; + NSDictionary* json = [NSJSONSerialization JSONObjectWithData:pcData options:0 error:&error]; NSAssert(!error, @"Unable to parse. %@", error.localizedDescription); - NSArray *servers = [json objectForKey:@"iceServers"]; - NSMutableArray *ICEServers = [NSMutableArray array]; - for (NSDictionary *server in servers) { - NSString *url = [server objectForKey:@"urls"]; - NSString *username = json[@"username"]; - NSString *credential = [server objectForKey:@"credential"]; + NSArray* servers = [json objectForKey:@"iceServers"]; + NSMutableArray* ICEServers = [NSMutableArray array]; + for (NSDictionary* server in servers) { + NSString* url = [server objectForKey:@"urls"]; + NSString* username = json[@"username"]; + NSString* credential = [server objectForKey:@"credential"]; if (!username) { username = @""; } if (!credential) { credential = @""; } - [self maybeLogMessage: - [NSString stringWithFormat:@"url [%@] - credential [%@]", - url, - credential]]; - RTCICEServer *ICEServer = + [self maybeLogMessage:[NSString + stringWithFormat:@"url [%@] - credential [%@]", + url, + credential]]; + RTCICEServer* ICEServer = [[RTCICEServer alloc] initWithURI:[NSURL URLWithString:url] username:username password:credential]; @@ -340,18 +333,19 @@ NSString* mc = [self findVar:@"mediaConstraints" strippingQuotes:NO]; if (mc) { error = nil; - NSData *mcData = [mc dataUsingEncoding:NSUTF8StringEncoding]; + NSData* mcData = [mc dataUsingEncoding:NSUTF8StringEncoding]; json = - [NSJSONSerialization JSONObjectWithData:mcData options:0 error:&error]; + [NSJSONSerialization JSONObjectWithData:mcData options:0 error:&error]; NSAssert(!error, @"Unable to parse. %@", error.localizedDescription); if ([[json objectForKey:@"video"] boolValue]) { - self.videoConstraints = [[RTCMediaConstraints alloc] init]; + _videoConstraints = [[RTCMediaConstraints alloc] init]; } } - [self maybeLogMessage: - [NSString stringWithFormat:@"About to open GAE with token: %@", - self.token]]; + [self + maybeLogMessage:[NSString + stringWithFormat:@"About to open GAE with token: %@", + self.token]]; self.gaeChannel = [[GAEChannelClient alloc] initWithToken:self.token delegate:self.messageHandler]; diff --git a/examples/ios/AppRTCDemo/APPRTCAppDelegate.h b/examples/ios/AppRTCDemo/APPRTCAppDelegate.h index 22a0225..517cade 100644 --- a/examples/ios/AppRTCDemo/APPRTCAppDelegate.h +++ b/examples/ios/AppRTCDemo/APPRTCAppDelegate.h @@ -34,9 +34,9 @@ // Used to send a message to an apprtc.appspot.com "room". @protocol APPRTCSendMessage<NSObject> -- (void)sendData:(NSData *)data; +- (void)sendData:(NSData*)data; // Logging helper. -- (void)displayLogMessage:(NSString *)message; +- (void)displayLogMessage:(NSString*)message; @end @class APPRTCViewController; @@ -51,8 +51,8 @@ RTCSessionDescriptonDelegate, UIApplicationDelegate> -@property (strong, nonatomic) UIWindow *window; -@property (strong, nonatomic) APPRTCViewController *viewController; +@property(strong, nonatomic) UIWindow* window; +@property(strong, nonatomic) APPRTCViewController* viewController; - (void)closeVideoUI; diff --git a/examples/ios/AppRTCDemo/APPRTCAppDelegate.m b/examples/ios/AppRTCDemo/APPRTCAppDelegate.m index 681876e..ee36604 100644 --- a/examples/ios/AppRTCDemo/APPRTCAppDelegate.m +++ b/examples/ios/AppRTCDemo/APPRTCAppDelegate.m @@ -42,13 +42,13 @@ #import "RTCVideoRenderer.h" #import "RTCVideoCapturer.h" #import "RTCVideoTrack.h" -#import "VideoView.h" +#import "APPRTCVideoView.h" @interface PCObserver : NSObject<RTCPeerConnectionDelegate> - (id)initWithDelegate:(id<APPRTCSendMessage>)delegate; -@property(nonatomic, strong) VideoView *videoView; +@property(nonatomic, strong) APPRTCVideoView* videoView; @end @@ -56,8 +56,6 @@ id<APPRTCSendMessage> _delegate; } -@synthesize videoView = _videoView; - - (id)initWithDelegate:(id<APPRTCSendMessage>)delegate { if (self = [super init]) { _delegate = delegate; @@ -65,70 +63,71 @@ return self; } -- (void)peerConnectionOnError:(RTCPeerConnection *)peerConnection { +- (void)peerConnectionOnError:(RTCPeerConnection*)peerConnection { NSLog(@"PCO onError."); NSAssert(NO, @"PeerConnection failed."); } -- (void)peerConnection:(RTCPeerConnection *)peerConnection +- (void)peerConnection:(RTCPeerConnection*)peerConnection signalingStateChanged:(RTCSignalingState)stateChanged { NSLog(@"PCO onSignalingStateChange: %d", stateChanged); } -- (void)peerConnection:(RTCPeerConnection *)peerConnection - addedStream:(RTCMediaStream *)stream { +- (void)peerConnection:(RTCPeerConnection*)peerConnection + addedStream:(RTCMediaStream*)stream { NSLog(@"PCO onAddStream."); dispatch_async(dispatch_get_main_queue(), ^(void) { - NSAssert([stream.audioTracks count] >= 1, - @"Expected at least 1 audio stream"); - NSAssert([stream.videoTracks count] <= 1, - @"Expected at most 1 video stream"); - if ([stream.videoTracks count] != 0) { - [[self videoView] - renderVideoTrackInterface:[stream.videoTracks objectAtIndex:0]]; - } + NSAssert([stream.audioTracks count] >= 1, + @"Expected at least 1 audio stream"); + NSAssert([stream.videoTracks count] <= 1, + @"Expected at most 1 video stream"); + if ([stream.videoTracks count] != 0) { + [self.videoView + renderVideoTrackInterface:[stream.videoTracks objectAtIndex:0]]; + } }); } -- (void)peerConnection:(RTCPeerConnection *)peerConnection - removedStream:(RTCMediaStream *)stream { +- (void)peerConnection:(RTCPeerConnection*)peerConnection + removedStream:(RTCMediaStream*)stream { NSLog(@"PCO onRemoveStream."); } -- (void) - peerConnectionOnRenegotiationNeeded:(RTCPeerConnection *)peerConnection { +- (void)peerConnectionOnRenegotiationNeeded:(RTCPeerConnection*)peerConnection { NSLog(@"PCO onRenegotiationNeeded."); // TODO(hughv): Handle this. } -- (void)peerConnection:(RTCPeerConnection *)peerConnection - gotICECandidate:(RTCICECandidate *)candidate { +- (void)peerConnection:(RTCPeerConnection*)peerConnection + gotICECandidate:(RTCICECandidate*)candidate { NSLog(@"PCO onICECandidate.\n Mid[%@] Index[%d] Sdp[%@]", candidate.sdpMid, candidate.sdpMLineIndex, candidate.sdp); - NSDictionary *json = - @{ @"type" : @"candidate", - @"label" : [NSNumber numberWithInt:candidate.sdpMLineIndex], - @"id" : candidate.sdpMid, - @"candidate" : candidate.sdp }; - NSError *error; - NSData *data = + NSDictionary* json = @{ + @"type" : @"candidate", + @"label" : [NSNumber numberWithInt:candidate.sdpMLineIndex], + @"id" : candidate.sdpMid, + @"candidate" : candidate.sdp + }; + NSError* error; + NSData* data = [NSJSONSerialization dataWithJSONObject:json options:0 error:&error]; if (!error) { [_delegate sendData:data]; } else { - NSAssert(NO, @"Unable to serialize JSON object with error: %@", + NSAssert(NO, + @"Unable to serialize JSON object with error: %@", error.localizedDescription); } } -- (void)peerConnection:(RTCPeerConnection *)peerConnection +- (void)peerConnection:(RTCPeerConnection*)peerConnection iceGatheringChanged:(RTCICEGatheringState)newState { NSLog(@"PCO onIceGatheringChange. %d", newState); } -- (void)peerConnection:(RTCPeerConnection *)peerConnection +- (void)peerConnection:(RTCPeerConnection*)peerConnection iceConnectionChanged:(RTCICEConnectionState)newState { NSLog(@"PCO onIceConnectionChange. %d", newState); if (newState == RTCICEConnectionConnected) @@ -136,7 +135,7 @@ NSAssert(newState != RTCICEConnectionFailed, @"ICE Connection failed!"); } -- (void)displayLogMessage:(NSString *)message { +- (void)displayLogMessage:(NSString*)message { [_delegate displayLogMessage:message]; } @@ -144,28 +143,20 @@ @interface APPRTCAppDelegate () -@property(nonatomic, strong) APPRTCAppClient *client; -@property(nonatomic, strong) PCObserver *pcObserver; -@property(nonatomic, strong) RTCPeerConnection *peerConnection; -@property(nonatomic, strong) RTCPeerConnectionFactory *peerConnectionFactory; -@property(nonatomic, strong) NSMutableArray *queuedRemoteCandidates; +@property(nonatomic, strong) APPRTCAppClient* client; +@property(nonatomic, strong) PCObserver* pcObserver; +@property(nonatomic, strong) RTCPeerConnection* peerConnection; +@property(nonatomic, strong) RTCPeerConnectionFactory* peerConnectionFactory; +@property(nonatomic, strong) NSMutableArray* queuedRemoteCandidates; @end @implementation APPRTCAppDelegate -@synthesize window = _window; -@synthesize viewController = _viewController; -@synthesize client = _client; -@synthesize pcObserver = _pcObserver; -@synthesize peerConnection = _peerConnection; -@synthesize peerConnectionFactory = _peerConnectionFactory; -@synthesize queuedRemoteCandidates = _queuedRemoteCandidates; - #pragma mark - UIApplicationDelegate methods -- (BOOL)application:(UIApplication *)application - didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { +- (BOOL)application:(UIApplication*)application + didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { [RTCPeerConnectionFactory initializeSSL]; self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; self.viewController = @@ -176,100 +167,97 @@ return YES; } -- (void)applicationWillResignActive:(UIApplication *)application { +- (void)applicationWillResignActive:(UIApplication*)application { [self displayLogMessage:@"Application lost focus, connection broken."]; [self closeVideoUI]; } -- (void)applicationDidEnterBackground:(UIApplication *)application { +- (void)applicationDidEnterBackground:(UIApplication*)application { } -- (void)applicationWillEnterForeground:(UIApplication *)application { +- (void)applicationWillEnterForeground:(UIApplication*)application { } -- (void)applicationDidBecomeActive:(UIApplication *)application { +- (void)applicationDidBecomeActive:(UIApplication*)application { } -- (void)applicationWillTerminate:(UIApplication *)application { +- (void)applicationWillTerminate:(UIApplication*)application { } -- (BOOL)application:(UIApplication *)application - openURL:(NSURL *)url - sourceApplication:(NSString *)sourceApplication +- (BOOL)application:(UIApplication*)application + openURL:(NSURL*)url + sourceApplication:(NSString*)sourceApplication annotation:(id)annotation { if (self.client) { return NO; } - self.client = [[APPRTCAppClient alloc] init]; - self.client.ICEServerDelegate = self; - self.client.messageHandler = self; + self.client = [[APPRTCAppClient alloc] initWithICEServerDelegate:self + messageHandler:self]; [self.client connectToRoom:url]; return YES; } -- (void)displayLogMessage:(NSString *)message { +- (void)displayLogMessage:(NSString*)message { NSLog(@"%@", message); [self.viewController displayText:message]; } #pragma mark - RTCSendMessage method -- (void)sendData:(NSData *)data { +- (void)sendData:(NSData*)data { [self.client sendData:data]; } #pragma mark - ICEServerDelegate method -- (void)onICEServers:(NSArray *)servers { +- (void)onICEServers:(NSArray*)servers { self.queuedRemoteCandidates = [NSMutableArray array]; self.peerConnectionFactory = [[RTCPeerConnectionFactory alloc] init]; - RTCMediaConstraints *constraints = [[RTCMediaConstraints alloc] - initWithMandatoryConstraints: - @[[[RTCPair alloc] - initWithKey:@"OfferToReceiveAudio" - value:@"true"], - [[RTCPair alloc] - initWithKey:@"OfferToReceiveVideo" - value:@"true"]] - optionalConstraints: - @[[[RTCPair alloc] - initWithKey:@"internalSctpDataChannels" - value:@"true"], - [[RTCPair alloc] - initWithKey:@"DtlsSrtpKeyAgreement" - value:@"true"]]]; + RTCMediaConstraints* constraints = [[RTCMediaConstraints alloc] + initWithMandatoryConstraints: + @[ + [[RTCPair alloc] initWithKey:@"OfferToReceiveAudio" value:@"true"], + [[RTCPair alloc] initWithKey:@"OfferToReceiveVideo" value:@"true"] + ] + optionalConstraints: + @[ + [[RTCPair alloc] initWithKey:@"internalSctpDataChannels" + value:@"true"], + [[RTCPair alloc] initWithKey:@"DtlsSrtpKeyAgreement" + value:@"true"] + ]]; self.pcObserver = [[PCObserver alloc] initWithDelegate:self]; self.peerConnection = [self.peerConnectionFactory peerConnectionWithICEServers:servers constraints:constraints delegate:self.pcObserver]; - RTCMediaStream *lms = + RTCMediaStream* lms = [self.peerConnectionFactory mediaStreamWithLabel:@"ARDAMS"]; - NSString *cameraID = nil; - for (AVCaptureDevice *captureDevice in - [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo] ) { - if (captureDevice.position == AVCaptureDevicePositionFront) { - cameraID = [captureDevice localizedName]; - break; - } + NSString* cameraID = nil; + for (AVCaptureDevice* captureDevice in + [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) { + if (captureDevice.position == AVCaptureDevicePositionFront) { + cameraID = [captureDevice localizedName]; + break; + } } NSAssert(cameraID, @"Unable to get the front camera id"); - RTCVideoCapturer *capturer = - [RTCVideoCapturer capturerWithDeviceName:cameraID]; - RTCVideoSource *videoSource = - [self.peerConnectionFactory - videoSourceWithCapturer:capturer constraints:self.client.videoConstraints]; - RTCVideoTrack *localVideoTrack = - [self.peerConnectionFactory - videoTrackWithID:@"ARDAMSv0" source:videoSource]; + RTCVideoCapturer* capturer = + [RTCVideoCapturer capturerWithDeviceName:cameraID]; + RTCVideoSource* videoSource = [self.peerConnectionFactory + videoSourceWithCapturer:capturer + constraints:self.client.videoConstraints]; + RTCVideoTrack* localVideoTrack = + [self.peerConnectionFactory videoTrackWithID:@"ARDAMSv0" + source:videoSource]; if (localVideoTrack) { - [lms addVideoTrack:localVideoTrack]; + [lms addVideoTrack:localVideoTrack]; } [self.viewController.localVideoView - renderVideoTrackInterface:localVideoTrack]; + renderVideoTrackInterface:localVideoTrack]; self.pcObserver.videoView = self.viewController.remoteVideoView; @@ -282,26 +270,26 @@ - (void)onOpen { if (!self.client.initiator) { - [self displayLogMessage:@"Callee; waiting for remote offer"]; - return; + [self displayLogMessage:@"Callee; waiting for remote offer"]; + return; } [self displayLogMessage:@"GAE onOpen - create offer."]; - RTCPair *audio = + RTCPair* audio = [[RTCPair alloc] initWithKey:@"OfferToReceiveAudio" value:@"true"]; - RTCPair *video = [[RTCPair alloc] initWithKey:@"OfferToReceiveVideo" - value:@"true"]; - NSArray *mandatory = @[ audio , video ]; - RTCMediaConstraints *constraints = + RTCPair* video = + [[RTCPair alloc] initWithKey:@"OfferToReceiveVideo" value:@"true"]; + NSArray* mandatory = @[ audio, video ]; + RTCMediaConstraints* constraints = [[RTCMediaConstraints alloc] initWithMandatoryConstraints:mandatory optionalConstraints:nil]; [self.peerConnection createOfferWithDelegate:self constraints:constraints]; [self displayLogMessage:@"PC - createOffer."]; } -- (void)onMessage:(NSString *)data { - NSString *message = [self unHTMLifyString:data]; - NSError *error; - NSDictionary *objects = [NSJSONSerialization +- (void)onMessage:(NSString*)data { + NSString* message = [self unHTMLifyString:data]; + NSError* error; + NSDictionary* objects = [NSJSONSerialization JSONObjectWithData:[message dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&error]; @@ -309,14 +297,14 @@ @"%@", [NSString stringWithFormat:@"Error: %@", error.description]); NSAssert([objects count] > 0, @"Invalid JSON object"); - NSString *value = [objects objectForKey:@"type"]; - [self displayLogMessage: - [NSString stringWithFormat:@"GAE onMessage type - %@", value]]; + NSString* value = [objects objectForKey:@"type"]; + [self displayLogMessage:[NSString stringWithFormat:@"GAE onMessage type - %@", + value]]; if ([value compare:@"candidate"] == NSOrderedSame) { - NSString *mid = [objects objectForKey:@"id"]; - NSNumber *sdpLineIndex = [objects objectForKey:@"label"]; - NSString *sdp = [objects objectForKey:@"candidate"]; - RTCICECandidate *candidate = + NSString* mid = [objects objectForKey:@"id"]; + NSNumber* sdpLineIndex = [objects objectForKey:@"label"]; + NSString* sdp = [objects objectForKey:@"candidate"]; + RTCICECandidate* candidate = [[RTCICECandidate alloc] initWithMid:mid index:sdpLineIndex.intValue sdp:sdp]; @@ -327,20 +315,21 @@ } } else if (([value compare:@"offer"] == NSOrderedSame) || ([value compare:@"answer"] == NSOrderedSame)) { - NSString *sdpString = [objects objectForKey:@"sdp"]; - RTCSessionDescription *sdp = [[RTCSessionDescription alloc] - initWithType:value sdp:[APPRTCAppDelegate preferISAC:sdpString]]; + NSString* sdpString = [objects objectForKey:@"sdp"]; + RTCSessionDescription* sdp = [[RTCSessionDescription alloc] + initWithType:value + sdp:[APPRTCAppDelegate preferISAC:sdpString]]; [self.peerConnection setRemoteDescriptionWithDelegate:self sessionDescription:sdp]; [self displayLogMessage:@"PC - setRemoteDescription."]; } else if ([value compare:@"bye"] == NSOrderedSame) { [self closeVideoUI]; - UIAlertView *alertView = - [[UIAlertView alloc] initWithTitle:@"Remote end hung up" - message:@"dropping PeerConnection" - delegate:nil - cancelButtonTitle:@"OK" - otherButtonTitles:nil]; + UIAlertView* alertView = + [[UIAlertView alloc] initWithTitle:@"Remote end hung up" + message:@"dropping PeerConnection" + delegate:nil + cancelButtonTitle:@"OK" + otherButtonTitles:nil]; [alertView show]; } else { NSAssert(NO, @"Invalid message: %@", data); @@ -352,9 +341,9 @@ [self closeVideoUI]; } -- (void)onError:(int)code withDescription:(NSString *)description { - [self displayLogMessage: - [NSString stringWithFormat:@"GAE onError: %@", description]]; +- (void)onError:(int)code withDescription:(NSString*)description { + [self displayLogMessage:[NSString stringWithFormat:@"GAE onError: %@", + description]]; [self closeVideoUI]; } @@ -362,19 +351,19 @@ // 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 { ++ (NSString*)firstMatch:(NSRegularExpression*)pattern + withString:(NSString*)string { NSTextCheckingResult* result = - [pattern firstMatchInString:string - options:0 - range:NSMakeRange(0, [string length])]; + [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 { ++ (NSString*)preferISAC:(NSString*)origSDP { int mLineIndex = -1; NSString* isac16kRtpMap = nil; NSArray* lines = [origSDP componentsSeparatedByString:@"\n"]; @@ -411,8 +400,8 @@ [newMLine addObject:[origMLineParts objectAtIndex:origPartIndex++]]; [newMLine addObject:isac16kRtpMap]; for (; origPartIndex < [origMLineParts count]; ++origPartIndex) { - if ([isac16kRtpMap compare:[origMLineParts objectAtIndex:origPartIndex]] - != NSOrderedSame) { + if ([isac16kRtpMap compare:[origMLineParts objectAtIndex:origPartIndex]] != + NSOrderedSame) { [newMLine addObject:[origMLineParts objectAtIndex:origPartIndex]]; } } @@ -423,9 +412,9 @@ return [newLines componentsJoinedByString:@"\n"]; } -- (void)peerConnection:(RTCPeerConnection *)peerConnection - didCreateSessionDescription:(RTCSessionDescription *)origSdp - error:(NSError *)error { +- (void)peerConnection:(RTCPeerConnection*)peerConnection + didCreateSessionDescription:(RTCSessionDescription*)origSdp + error:(NSError*)error { if (error) { [self displayLogMessage:@"SDP onFailure."]; NSAssert(NO, error.description); @@ -433,27 +422,26 @@ } [self displayLogMessage:@"SDP onSuccess(SDP) - set local description."]; - RTCSessionDescription* sdp = - [[RTCSessionDescription alloc] - initWithType:origSdp.type - sdp:[APPRTCAppDelegate preferISAC:origSdp.description]]; + RTCSessionDescription* sdp = [[RTCSessionDescription alloc] + initWithType:origSdp.type + sdp:[APPRTCAppDelegate preferISAC:origSdp.description]]; [self.peerConnection setLocalDescriptionWithDelegate:self sessionDescription:sdp]; [self displayLogMessage:@"PC setLocalDescription."]; dispatch_async(dispatch_get_main_queue(), ^(void) { - NSDictionary *json = @{ @"type" : sdp.type, @"sdp" : sdp.description }; - NSError *error; - NSData *data = - [NSJSONSerialization dataWithJSONObject:json options:0 error:&error]; - NSAssert(!error, - @"%@", - [NSString stringWithFormat:@"Error: %@", error.description]); - [self sendData:data]; + NSDictionary* json = @{@"type" : sdp.type, @"sdp" : sdp.description}; + NSError* error; + NSData* data = + [NSJSONSerialization dataWithJSONObject:json options:0 error:&error]; + NSAssert(!error, + @"%@", + [NSString stringWithFormat:@"Error: %@", error.description]); + [self sendData:data]; }); } -- (void)peerConnection:(RTCPeerConnection *)peerConnection - didSetSessionDescriptionWithError:(NSError *)error { +- (void)peerConnection:(RTCPeerConnection*)peerConnection + didSetSessionDescriptionWithError:(NSError*)error { if (error) { [self displayLogMessage:@"SDP onFailure."]; NSAssert(NO, error.description); @@ -462,34 +450,31 @@ [self displayLogMessage:@"SDP onSuccess() - possibly drain candidates"]; dispatch_async(dispatch_get_main_queue(), ^(void) { - if (!self.client.initiator) { - if (self.peerConnection.remoteDescription - && !self.peerConnection.localDescription) { - [self displayLogMessage:@"Callee, setRemoteDescription succeeded"]; - RTCPair *audio = - [[RTCPair alloc] - initWithKey:@"OfferToReceiveAudio" value:@"true"]; - RTCPair *video = - [[RTCPair alloc] - initWithKey:@"OfferToReceiveVideo" value:@"true"]; - NSArray *mandatory = @[ audio , video ]; - RTCMediaConstraints *constraints = - [[RTCMediaConstraints alloc] - initWithMandatoryConstraints:mandatory - optionalConstraints:nil]; - [self.peerConnection - createAnswerWithDelegate:self constraints:constraints]; - [self displayLogMessage:@"PC - createAnswer."]; + if (!self.client.initiator) { + if (self.peerConnection.remoteDescription && + !self.peerConnection.localDescription) { + [self displayLogMessage:@"Callee, setRemoteDescription succeeded"]; + RTCPair* audio = [[RTCPair alloc] initWithKey:@"OfferToReceiveAudio" + value:@"true"]; + RTCPair* video = [[RTCPair alloc] initWithKey:@"OfferToReceiveVideo" + value:@"true"]; + NSArray* mandatory = @[ audio, video ]; + RTCMediaConstraints* constraints = [[RTCMediaConstraints alloc] + initWithMandatoryConstraints:mandatory + optionalConstraints:nil]; + [self.peerConnection createAnswerWithDelegate:self + constraints:constraints]; + [self displayLogMessage:@"PC - createAnswer."]; } else { - [self displayLogMessage:@"SDP onSuccess - drain candidates"]; - [self drainRemoteCandidates]; + [self displayLogMessage:@"SDP onSuccess - drain candidates"]; + [self drainRemoteCandidates]; } - } else { + } else { if (self.peerConnection.remoteDescription) { - [self displayLogMessage:@"SDP onSuccess - drain candidates"]; - [self drainRemoteCandidates]; + [self displayLogMessage:@"SDP onSuccess - drain candidates"]; + [self drainRemoteCandidates]; } - } + } }); } @@ -502,36 +487,34 @@ self.peerConnection = nil; self.peerConnectionFactory = nil; self.pcObserver = nil; - self.client.ICEServerDelegate = nil; - self.client.messageHandler = nil; self.client = nil; [RTCPeerConnectionFactory deinitializeSSL]; } - (void)drainRemoteCandidates { - for (RTCICECandidate *candidate in self.queuedRemoteCandidates) { + for (RTCICECandidate* candidate in self.queuedRemoteCandidates) { [self.peerConnection addICECandidate:candidate]; } self.queuedRemoteCandidates = nil; } -- (NSString *)unHTMLifyString:(NSString *)base { +- (NSString*)unHTMLifyString:(NSString*)base { // TODO(hughv): Investigate why percent escapes are being added. Removing // them isn't necessary on Android. // convert HTML escaped characters to UTF8. - NSString *removePercent = + NSString* removePercent = [base stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; // remove leading and trailing ". NSRange range; range.length = [removePercent length] - 2; range.location = 1; - NSString *removeQuotes = [removePercent substringWithRange:range]; + NSString* removeQuotes = [removePercent substringWithRange:range]; // convert \" to ". - NSString *removeEscapedQuotes = + NSString* removeEscapedQuotes = [removeQuotes stringByReplacingOccurrencesOfString:@"\\\"" withString:@"\""]; // convert \\ to \. - NSString *removeBackslash = + NSString* removeBackslash = [removeEscapedQuotes stringByReplacingOccurrencesOfString:@"\\\\" withString:@"\\"]; return removeBackslash; @@ -540,8 +523,8 @@ #pragma mark - public methods - (void)closeVideoUI { - [self disconnect]; - [self.viewController resetUI]; + [self disconnect]; + [self.viewController resetUI]; } @end diff --git a/examples/ios/AppRTCDemo/VideoView.h b/examples/ios/AppRTCDemo/APPRTCVideoView.h index ff3167c..238798e 100644 --- a/examples/ios/AppRTCDemo/VideoView.h +++ b/examples/ios/AppRTCDemo/APPRTCVideoView.h @@ -30,7 +30,7 @@ @class RTCVideoTrack; // This class encapsulates VideoRenderIosView. -@interface VideoView : UIView +@interface APPRTCVideoView : UIView // Property to get/set required video orientation. @property(nonatomic, assign) UIInterfaceOrientation videoOrientation; @@ -40,11 +40,4 @@ // Sets up the underlying renderer and track objects. - (void)renderVideoTrackInterface:(RTCVideoTrack*)track; -// Stops rendering. -- (void)pause; -// Starts rendering. -- (void)resume; -// Stops rendering and resets underlying renderer and track objects. -- (void)stop; - @end diff --git a/examples/ios/AppRTCDemo/APPRTCVideoView.m b/examples/ios/AppRTCDemo/APPRTCVideoView.m new file mode 100644 index 0000000..23466b6 --- /dev/null +++ b/examples/ios/AppRTCDemo/APPRTCVideoView.m @@ -0,0 +1,82 @@ +/* + * libjingle + * Copyright 2013, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This APPRTCVideoView must be initialzed and added to a View to get + * either the local or remote video stream rendered. + * It is a view itself and it encapsulates + * an object of VideoRenderIosView and UIActivityIndicatorView. + * Both of the views will get resized as per the frame of their parent. + */ + +#import "APPRTCVideoView.h" + +#import "RTCVideoRenderer.h" +#import "RTCVideoTrack.h" + +@interface APPRTCVideoView () { + RTCVideoTrack* _track; + RTCVideoRenderer* _renderer; +} + +@property(nonatomic, weak) UIView* renderView; +@property(nonatomic, weak) UIActivityIndicatorView* activityView; + +@end + +@implementation APPRTCVideoView + +@synthesize videoOrientation = _videoOrientation; + +- (void)layoutSubviews { + [super layoutSubviews]; + if (!_renderer) { + // Left-right (mirror) flip the remote view. + CGAffineTransform xform = + CGAffineTransformMakeScale(self.isRemote ? -1 : 1, 1); + // TODO(fischman): why is this rotate (vertical+horizontal flip) needed?!? + xform = CGAffineTransformRotate(xform, M_PI); + // TODO(fischman): ensure back-camera flip is correct in all orientations, + // when back-camera support is added. + [self setTransform:xform]; + _renderer = [[RTCVideoRenderer alloc] initWithView:self]; + } +} + +- (void)renderVideoTrackInterface:(RTCVideoTrack*)videoTrack { + [_track removeRenderer:_renderer]; + [_renderer stop]; + + _track = videoTrack; + + if (_track) { + [_track addRenderer:_renderer]; + [_renderer start]; + } +} + +@end diff --git a/examples/ios/AppRTCDemo/APPRTCViewController.h b/examples/ios/AppRTCDemo/APPRTCViewController.h index 2db01a6..c42a372 100644 --- a/examples/ios/AppRTCDemo/APPRTCViewController.h +++ b/examples/ios/AppRTCDemo/APPRTCViewController.h @@ -27,20 +27,20 @@ #import <UIKit/UIKit.h> -@class VideoView; +@class APPRTCVideoView; // The view controller that is displayed when AppRTCDemo is loaded. @interface APPRTCViewController : UIViewController<UITextFieldDelegate> -@property (weak, nonatomic) IBOutlet UITextField *textField; -@property (weak, nonatomic) IBOutlet UITextView *textInstructions; -@property (weak, nonatomic) IBOutlet UITextView *textOutput; +@property(weak, nonatomic) IBOutlet UITextField* textField; +@property(weak, nonatomic) IBOutlet UITextView* textInstructions; +@property(weak, nonatomic) IBOutlet UITextView* textOutput; @property(weak, nonatomic) IBOutlet UIView* blackView; -@property(nonatomic, strong) VideoView* remoteVideoView; -@property(nonatomic, strong) VideoView* localVideoView; +@property(nonatomic, strong) APPRTCVideoView* remoteVideoView; +@property(nonatomic, strong) APPRTCVideoView* localVideoView; -- (void)displayText:(NSString *)text; +- (void)displayText:(NSString*)text; - (void)resetUI; @end diff --git a/examples/ios/AppRTCDemo/APPRTCViewController.m b/examples/ios/AppRTCDemo/APPRTCViewController.m index cacac14..8c5ccde 100644 --- a/examples/ios/AppRTCDemo/APPRTCViewController.m +++ b/examples/ios/AppRTCDemo/APPRTCViewController.m @@ -27,49 +27,40 @@ #import "APPRTCViewController.h" -#import "VideoView.h" +#import "APPRTCVideoView.h" @interface APPRTCViewController () -@property (nonatomic, assign) UIInterfaceOrientation statusBarOrientation; +@property(nonatomic, assign) UIInterfaceOrientation statusBarOrientation; @end @implementation APPRTCViewController -@synthesize textField = _textField; -@synthesize textInstructions = _textInstructions; -@synthesize textOutput = _textOutput; -@synthesize blackView = _blackView; - -@synthesize remoteVideoView = _remoteVideoView; -@synthesize localVideoView = _localVideoView; - -@synthesize statusBarOrientation = _statusBarOrientation; - - (void)viewDidLoad { [super viewDidLoad]; self.statusBarOrientation = - [UIApplication sharedApplication].statusBarOrientation; + [UIApplication sharedApplication].statusBarOrientation; self.textField.delegate = self; [self.textField becomeFirstResponder]; } - (void)viewDidLayoutSubviews { - if (self.statusBarOrientation != - [UIApplication sharedApplication].statusBarOrientation) { - self.statusBarOrientation = - [UIApplication sharedApplication].statusBarOrientation; - [[NSNotificationCenter defaultCenter] - postNotificationName:@"StatusBarOrientationDidChange" object:nil]; - } + if (self.statusBarOrientation != + [UIApplication sharedApplication].statusBarOrientation) { + self.statusBarOrientation = + [UIApplication sharedApplication].statusBarOrientation; + [[NSNotificationCenter defaultCenter] + postNotificationName:@"StatusBarOrientationDidChange" + object:nil]; + } } -- (void)displayText:(NSString *)text { +- (void)displayText:(NSString*)text { dispatch_async(dispatch_get_main_queue(), ^(void) { - NSString *output = - [NSString stringWithFormat:@"%@\n%@", self.textOutput.text, text]; - self.textOutput.text = output; + NSString* output = + [NSString stringWithFormat:@"%@\n%@", self.textOutput.text, text]; + self.textOutput.text = output; }); } @@ -82,11 +73,11 @@ self.textOutput.text = nil; self.blackView.hidden = YES; - [_remoteVideoView stop]; + [_remoteVideoView renderVideoTrackInterface:nil]; [_remoteVideoView removeFromSuperview]; self.remoteVideoView = nil; - [_localVideoView stop]; + [_remoteVideoView renderVideoTrackInterface:nil]; [_localVideoView removeFromSuperview]; self.localVideoView = nil; } @@ -94,61 +85,62 @@ // TODO(fischman): Use video dimensions from the incoming video stream // and resize the Video View accordingly w.r.t. aspect ratio. enum { - // Remote video view dimensions. - kRemoteVideoWidth = 640, - kRemoteVideoHeight = 480, - // Padding space for local video view with its parent. - kLocalViewPadding = 20 + // Remote video view dimensions. + kRemoteVideoWidth = 640, + kRemoteVideoHeight = 480, + // Padding space for local video view with its parent. + kLocalViewPadding = 20 }; - (void)setupCaptureSession { - self.blackView.hidden = NO; - - CGRect frame = CGRectMake((self.blackView.bounds.size.width - -kRemoteVideoWidth)/2, - (self.blackView.bounds.size.height - -kRemoteVideoHeight)/2, - kRemoteVideoWidth, - kRemoteVideoHeight); - VideoView *videoView = [[VideoView alloc] initWithFrame:frame]; - videoView.isRemote = TRUE; - - [self.blackView addSubview:videoView]; - videoView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | - UIViewAutoresizingFlexibleRightMargin | - UIViewAutoresizingFlexibleBottomMargin | - UIViewAutoresizingFlexibleTopMargin; - videoView.translatesAutoresizingMaskIntoConstraints = YES; - _remoteVideoView = videoView; - - CGSize screenSize = [[UIScreen mainScreen] bounds].size; - CGFloat localVideoViewWidth = - UIInterfaceOrientationIsPortrait(self.statusBarOrientation) ? - screenSize.width/4 : screenSize.height/4; - CGFloat localVideoViewHeight = - UIInterfaceOrientationIsPortrait(self.statusBarOrientation) ? - screenSize.height/4 : screenSize.width/4; - frame = CGRectMake(self.blackView.bounds.size.width - -localVideoViewWidth-kLocalViewPadding, - kLocalViewPadding, - localVideoViewWidth, - localVideoViewHeight); - videoView = [[VideoView alloc] initWithFrame:frame]; - videoView.isRemote = FALSE; - - [self.blackView addSubview:videoView]; - videoView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | - UIViewAutoresizingFlexibleBottomMargin | - UIViewAutoresizingFlexibleHeight | - UIViewAutoresizingFlexibleWidth; - videoView.translatesAutoresizingMaskIntoConstraints = YES; - _localVideoView = videoView; + self.blackView.hidden = NO; + + CGRect frame = + CGRectMake((self.blackView.bounds.size.width - kRemoteVideoWidth) / 2, + (self.blackView.bounds.size.height - kRemoteVideoHeight) / 2, + kRemoteVideoWidth, + kRemoteVideoHeight); + APPRTCVideoView* videoView = [[APPRTCVideoView alloc] initWithFrame:frame]; + videoView.isRemote = TRUE; + + [self.blackView addSubview:videoView]; + videoView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | + UIViewAutoresizingFlexibleRightMargin | + UIViewAutoresizingFlexibleBottomMargin | + UIViewAutoresizingFlexibleTopMargin; + videoView.translatesAutoresizingMaskIntoConstraints = YES; + _remoteVideoView = videoView; + + CGSize screenSize = [[UIScreen mainScreen] bounds].size; + CGFloat localVideoViewWidth = + UIInterfaceOrientationIsPortrait(self.statusBarOrientation) + ? screenSize.width / 4 + : screenSize.height / 4; + CGFloat localVideoViewHeight = + UIInterfaceOrientationIsPortrait(self.statusBarOrientation) + ? screenSize.height / 4 + : screenSize.width / 4; + frame = CGRectMake(self.blackView.bounds.size.width - localVideoViewWidth - + kLocalViewPadding, + kLocalViewPadding, + localVideoViewWidth, + localVideoViewHeight); + videoView = [[APPRTCVideoView alloc] initWithFrame:frame]; + videoView.isRemote = FALSE; + + [self.blackView addSubview:videoView]; + videoView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | + UIViewAutoresizingFlexibleBottomMargin | + UIViewAutoresizingFlexibleHeight | + UIViewAutoresizingFlexibleWidth; + videoView.translatesAutoresizingMaskIntoConstraints = YES; + _localVideoView = videoView; } #pragma mark - UITextFieldDelegate -- (void)textFieldDidEndEditing:(UITextField *)textField { - NSString *room = textField.text; +- (void)textFieldDidEndEditing:(UITextField*)textField { + NSString* room = textField.text; if ([room length] == 0) { return; } @@ -159,16 +151,14 @@ enum { // prepopulating the textField with a valid URL missing the room. This allows // the user to have the simplicity of just entering the room or the ability to // override to a custom appspot instance. Remove apprtc:// when this is done. - NSString *url = + NSString* url = [NSString stringWithFormat:@"apprtc://apprtc.appspot.com/?r=%@", room]; [[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]]; - dispatch_async(dispatch_get_main_queue(), ^{ - [self setupCaptureSession]; - }); + dispatch_async(dispatch_get_main_queue(), ^{ [self setupCaptureSession]; }); } -- (BOOL)textFieldShouldReturn:(UITextField *)textField { +- (BOOL)textFieldShouldReturn:(UITextField*)textField { // There is no other control that can take focus, so manually resign focus // when return (Join) is pressed to trigger |textFieldDidEndEditing|. [textField resignFirstResponder]; diff --git a/examples/ios/AppRTCDemo/GAEChannelClient.m b/examples/ios/AppRTCDemo/GAEChannelClient.m index e0d9a80..1b5e559 100644 --- a/examples/ios/AppRTCDemo/GAEChannelClient.m +++ b/examples/ios/AppRTCDemo/GAEChannelClient.m @@ -32,27 +32,23 @@ @interface GAEChannelClient () @property(nonatomic, assign) id<GAEMessageHandler> delegate; -@property(nonatomic, strong) UIWebView *webView; +@property(nonatomic, strong) UIWebView* webView; @end @implementation GAEChannelClient -@synthesize delegate = _delegate; -@synthesize webView = _webView; - -- (id)initWithToken:(NSString *)token delegate:(id<GAEMessageHandler>)delegate { +- (id)initWithToken:(NSString*)token delegate:(id<GAEMessageHandler>)delegate { self = [super init]; if (self) { _webView = [[UIWebView alloc] init]; _webView.delegate = self; _delegate = delegate; - NSString *htmlPath = + NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"ios_channel" ofType:@"html"]; - NSURL *htmlUrl = [NSURL fileURLWithPath:htmlPath]; - NSString *path = [NSString stringWithFormat:@"%@?token=%@", - [htmlUrl absoluteString], - token]; + NSURL* htmlUrl = [NSURL fileURLWithPath:htmlPath]; + NSString* path = [NSString + stringWithFormat:@"%@?token=%@", [htmlUrl absoluteString], token]; [_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:path]]]; @@ -67,17 +63,17 @@ #pragma mark - UIWebViewDelegate method -- (BOOL)webView:(UIWebView *)webView - shouldStartLoadWithRequest:(NSURLRequest *)request +- (BOOL)webView:(UIWebView*)webView + shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType { - NSString *scheme = [request.URL scheme]; + NSString* scheme = [request.URL scheme]; if ([scheme compare:@"js-frame"] != NSOrderedSame) { return YES; } - NSString *resourceSpecifier = [request.URL resourceSpecifier]; + NSString* resourceSpecifier = [request.URL resourceSpecifier]; NSRange range = [resourceSpecifier rangeOfString:@":"]; - NSString *method; - NSString *message; + NSString* method; + NSString* message; if (range.length == 0 && range.location == NSNotFound) { method = resourceSpecifier; } else { @@ -85,21 +81,21 @@ message = [resourceSpecifier substringFromIndex:range.location + 1]; } dispatch_async(dispatch_get_main_queue(), ^(void) { - if ([method compare:@"onopen"] == NSOrderedSame) { - [self.delegate onOpen]; - } else if ([method compare:@"onmessage"] == NSOrderedSame) { - [self.delegate onMessage:message]; - } else if ([method compare:@"onclose"] == NSOrderedSame) { - [self.delegate onClose]; - } else if ([method compare:@"onerror"] == NSOrderedSame) { - // TODO(hughv): Get error. - int code = -1; - NSString *description = message; - [self.delegate onError:code withDescription:description]; - } else { - NSAssert(NO, @"Invalid message sent from UIWebView: %@", - resourceSpecifier); - } + if ([method compare:@"onopen"] == NSOrderedSame) { + [self.delegate onOpen]; + } else if ([method compare:@"onmessage"] == NSOrderedSame) { + [self.delegate onMessage:message]; + } else if ([method compare:@"onclose"] == NSOrderedSame) { + [self.delegate onClose]; + } else if ([method compare:@"onerror"] == NSOrderedSame) { + // TODO(hughv): Get error. + int code = -1; + NSString* description = message; + [self.delegate onError:code withDescription:description]; + } else { + NSAssert( + NO, @"Invalid message sent from UIWebView: %@", resourceSpecifier); + } }); return YES; } diff --git a/examples/ios/AppRTCDemo/VideoView.m b/examples/ios/AppRTCDemo/VideoView.m deleted file mode 100644 index d563fb3..0000000 --- a/examples/ios/AppRTCDemo/VideoView.m +++ /dev/null @@ -1,168 +0,0 @@ -/* - * libjingle - * Copyright 2013, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This VideoView must be initialzed and added to a View to get - * either the local or remote video stream rendered. - * It is a view itself and it encapsulates - * an object of VideoRenderIosView and UIActivityIndicatorView. - * Both of the views will get resized as per the frame of their parent. - */ - -#import "VideoView.h" - -#import "RTCVideoRenderer.h" -#import "RTCVideoTrack.h" - -@interface VideoView () { - RTCVideoTrack *_track; - RTCVideoRenderer *_renderer; -} - -@property (nonatomic, weak) UIView *renderView; -@property (nonatomic, weak) UIActivityIndicatorView *activityView; - -@end - -@implementation VideoView - -@synthesize videoOrientation = _videoOrientation; -@synthesize isRemote = _isRemote; -@synthesize renderView = _renderView; -@synthesize activityView = _activityView; - -static void init(VideoView *self) { - UIView *renderView = [RTCVideoRenderer newRenderViewWithFrame: - CGRectMake(0, - 0, - self.bounds.size.width, - self.bounds.size.height)]; - [self addSubview:renderView]; - renderView.autoresizingMask = UIViewAutoresizingFlexibleHeight | - UIViewAutoresizingFlexibleWidth; - renderView.translatesAutoresizingMaskIntoConstraints = YES; - self.renderView = renderView; - - UIActivityIndicatorView *indicatorView = - [[UIActivityIndicatorView alloc] - initWithActivityIndicatorStyle: - UIActivityIndicatorViewStyleWhiteLarge]; - indicatorView.frame = self.bounds; - indicatorView.hidesWhenStopped = YES; - [self addSubview:indicatorView]; - indicatorView.autoresizingMask = UIViewAutoresizingFlexibleWidth | - UIViewAutoresizingFlexibleHeight; - indicatorView.translatesAutoresizingMaskIntoConstraints = YES; - [indicatorView startAnimating]; - self.activityView = indicatorView; -} - -- (id)initWithFrame:(CGRect)frame { - self = [super initWithFrame:frame]; - if (self) { - init(self); - } - return self; -} - --(id)initWithCoder:(NSCoder *)aDecoder { - self = [super initWithCoder:aDecoder]; - if (self) { - init(self); - } - return self; -} - -- (UIInterfaceOrientation)videoOrientation { - return _videoOrientation; -} - -- (void)setVideoOrientation:(UIInterfaceOrientation)videoOrientation { - if (_videoOrientation != videoOrientation) { - _videoOrientation = videoOrientation; - - CGFloat angle; - switch (videoOrientation) { - case UIInterfaceOrientationPortrait: - angle = M_PI_2; - break; - case UIInterfaceOrientationPortraitUpsideDown: - angle = -M_PI_2; - break; - case UIInterfaceOrientationLandscapeLeft: - angle = M_PI; - break; - case UIInterfaceOrientationLandscapeRight: - angle = 0; - break; - } - // The video comes in mirrored. That is fine for the local video, - // but the remote video should be put back to original. - CGAffineTransform xform = - CGAffineTransformMakeScale([self isRemote] ? -1 : 1, 1); - xform = CGAffineTransformRotate(xform, angle); - [[self renderView] setTransform:xform]; - } -} - -- (void)renderVideoTrackInterface:(RTCVideoTrack *)videoTrack { - [self stop]; - - _track = videoTrack; - - if (_track) { - if (!_renderer) { - _renderer = [[RTCVideoRenderer alloc] - initWithRenderView:[self renderView]]; - } - [_track addRenderer:_renderer]; - [self resume]; - } - - [self setVideoOrientation:UIInterfaceOrientationLandscapeLeft]; - [self setVideoOrientation:UIInterfaceOrientationPortrait]; - [self setVideoOrientation:UIInterfaceOrientationLandscapeLeft]; -} - --(void)pause { - [_renderer stop]; -} - --(void)resume { - [self.activityView stopAnimating]; - [self.activityView removeFromSuperview]; - self.activityView = nil; - - [_renderer start]; -} - -- (void)stop { - [_track removeRenderer:_renderer]; - [_renderer stop]; -} - -@end diff --git a/examples/ios/AppRTCDemo/main.m b/examples/ios/AppRTCDemo/main.m index bf35f4c..e9a1f63 100644 --- a/examples/ios/AppRTCDemo/main.m +++ b/examples/ios/AppRTCDemo/main.m @@ -29,7 +29,7 @@ #import "APPRTCAppDelegate.h" -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { @autoreleasepool { return UIApplicationMain( argc, argv, nil, NSStringFromClass([APPRTCAppDelegate class])); |