Example of streamer for iOS
This streamer can be used to publish WebRTC video stream on Web Call Server.
...
- left - video from the camera
- right - the published video stream is played from the server
Work with code of the example
To analyze the code, let's take Streamer example version with hash c313c93, which can be downloaded with build build 2.5.2.4.
View class for the main view of the application: ViewController (header file ViewController.h; implementation file ViewController.m).
1. Import of API. ViewController.m, line 12 code
Code Block | ||||
---|---|---|---|---|
| ||||
#import <FPWCSApi2/FPWCSApi2.h> |
2. Connection to server.
ViewController method connect is called when Start button is tapped. ViewController.m, line 247
Code Block | ||||
---|---|---|---|---|
| ||||
[self connect]; |
In the method,
- object with options for connection session is created (ViewController.m, line 36Session creation.
FPWCSApi2 createSession code
The options include:
- URL of WCS server
- appKey of internal server-side application (defaultApp)
Code Block | ||||
---|---|---|---|---|
| ||||
FPWCSApi2SessionOptions *options = [[FPWCSApi2SessionOptions alloc] init]; .....NSURL *url =[[NSURL alloc] initWithString:_connectUrl.text]; options.urlServer = [NSString stringWithFormat:@"%@://%@:%@", url.scheme, url.host, url.port]; streamName = [url.....path.stringByDeletingPathExtension stringByReplacingOccurrencesOfString: @"/" withString:@""]; options.appKey = @"defaultApp"; NSError *error; |
The options include URL of WCS server and appKey of internal server-side application.
...
session = [FPWCSApi2 createSession:options error:&error]; |
3. Connection to the server
FPWCSApi2Session connect code
Code Block | ||||
---|---|---|---|---|
| ||||
[session connect]; |
4. Receiving the event confirming successful connection.
ViewController onConnected code
On this event, ViewController publishStream method is called to publish the stream
Code Block | ||||
---|---|---|---|---|
| ||||
- (void)onConnected:(FPWCSApi2Session *)session = [FPWCSApi2 createSession:options error:&error]; |
...
{
[_connectButton setTitle:@"STOP" forState:UIControlStateNormal];
// [self changeViewState:_connectButton enabled:YES];
[self publishStream];
} |
5. Stream publishing.
FPWCSApi2Session createStream, FPWCSApi2Stream publish code
Object with next stream options is passed to createStream method:
- stream name
- view to display video
- video constraints (for iPad for example)
Code Block | ||||
---|---|---|---|---|
| ||||
[session on:kFPWCSSessionStatusEstablished callback:^(FPWCSApi2Session- (FPWCSApi2Stream *rSession)publishStream { FPWCSApi2Session *session = [FPWCSApi2 [self changeConnectionStatus:[rSession getStatus]]getSessions][0]; FPWCSApi2StreamOptions *options = [[FPWCSApi2StreamOptions alloc] init]; options.name = streamName; [self onConnected:rSession]; }]; [session on:kFPWCSSessionStatusDisconnected callback:^(FPWCSApi2Session *rSession){ [self changeConnectionStatus:[rSession getStatus]]; [self onDisconnected]; }]; [session on:kFPWCSSessionStatusFailed callback:^(FPWCSApi2Session *rSession){ [self changeConnectionStatus:[rSession getStatus]]; [self onDisconnected]; }]; |
Depending on the session status, corresponding ViewController method will be called to make appropriate changes in controls of the interface
- if connection is successfully established: onConnected
- in case of disconnection, or connection failure: onDisconnected
- FPWCSApi2Session method connect is called to establish connection to server (ViewController.m, line 75)
Code Block | ||||
---|---|---|---|---|
| ||||
[session connect]; |
3. Stream publishing.
When connection to the server is established, ViewController method publishStream is called to publish the stream. ViewController.m, line 199
Code Block | ||||
---|---|---|---|---|
| ||||
[self publishStream]; |
In the method,
- object with stream publish options is created (ViewController.m, line 81)
Code Block | ||||
---|---|---|---|---|
| ||||
options.display = _videoView.local;
if ( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ) {
options.constraints = [[FPWCSApi2MediaConstraints alloc] initWithAudio:YES videoWidth:640 videoHeight:480 videoFps:15];
}
NSError *error;
publishStream = [session createStream:options error:&error];
...
if(![publishStream publish:&error]) {
UIAlertController * alert = [UIAlertController
alertControllerWithTitle:@"Failed to publish"
message:error.localizedDescription
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* okButton = [UIAlertAction
actionWithTitle:@"Ok"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
[self onUnpublished];
}];
[alert addAction:okButton];
[self presentViewController:alert animated:YES completion:nil];
}
return publishStream;
} |
6. Receiving the event confirming successful stream publishing.
ViewController onPublishing code
On this event, ViewController playStream method is called to play preview stream
Code Block | ||||
---|---|---|---|---|
| ||||
- (void)onPublishing:(FPWCSApi2Stream *)stream {
[self playStream];
} |
7. Preview stream playback.
FPWCSApi2Session createStream, FPWCSApi2Stream play code
Object with next stream options is passed to createStream method:
- stream name
- view to display video
Code Block | ||||
---|---|---|---|---|
| ||||
- (FPWCSApi2Stream *)playStream { FPWCSApi2Session *session = [FPWCSApi2 getSessions][0]; FPWCSApi2StreamOptions *options = [[FPWCSApi2StreamOptions alloc] init]; options.name = streamName; options.display = _videoView.local; |
The required options are stream name and view for displaying video.
Also, video constraints can be specified. E.g., in the example, constraints are added in case the iOS device is iPad:
Code Block | ||||
---|---|---|---|---|
| ||||
if ( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ) {
options.constraints = [[FPWCSApi2MediaConstraints alloc] initWithAudio:YES videoWidth:640 videoHeight:480 videoFps:15];
} |
- new stream is created with FPWCSApi2Session method createStream, which returns FPWCSApi2Stream object (ViewController.m, line 88)
Code Block | ||||
---|---|---|---|---|
| ||||
publishStream = [session createStream:options error:&error]; |
- callback functions for processing stream statuses are added (ViewController.m, line 106)
Code Block | ||||
---|---|---|---|---|
| ||||
[publishStream on:kFPWCSStreamStatusPublishing callback:^(FPWCSApi2Stream *rStream){
[self changeStreamStatus:rStream];
[self onPublishing:rStream];
}]; |
Depending on the stream status, corresponding ViewController method will be called to make appropriate changes in controls of the interface
- if stream is successfully published: onPublishing
- in case of failure, or when stream is unpublished: onUnpublished
- FPWCSApi2Stream method publish is called to publish the stream (ViewController.m, line 120)
Code Block | ||||
---|---|---|---|---|
| ||||
[publishStream publish:&error] |
4. Disconnection. ViewController.m, line 239
FPWCSApi2Session method disconnect is called to close connection to the server when Stop button is tapped.
Code Block | ||||
---|---|---|---|---|
| ||||
[session disconnect];remote; NSError *error; playStream = [session createStream:options error:nil]; ... if(![playStream play:&error]) { UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"Failed to play" message:error.localizedDescription preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction* okButton = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { }]; [alert addAction:okButton]; [self presentViewController:alert animated:YES completion:nil]; } return playStream; } |
8. Disconnection
FPWCSApi2Session disconnect code
Code Block | ||||
---|---|---|---|---|
| ||||
- (void)connectButton:(UIButton *)button {
[self changeViewState:button enabled:NO];
if ([button.titleLabel.text isEqualToString:@"STOP"]) {
if ([FPWCSApi2 getSessions].count) {
FPWCSApi2Session *session = [FPWCSApi2 getSessions][0];
NSLog(@"Disconnect session with server %@", [session getServerUrl]);
[session disconnect];
} else {
NSLog(@"Nothing to disconnect");
[self onDisconnected];
}
} else {
//todo check url is not empty
[self changeViewState:_connectUrl enabled:NO];
[self connect];
}
} |
9. Receiving the event confirming successful disconnection.
ViewController onDisconnected code
Code Block | ||||
---|---|---|---|---|
| ||||
- (void)onDisconnected {
[_connectButton setTitle:@"START" forState:UIControlStateNormal];
[self changeViewState:_connectButton enabled:YES];
[self changeViewState:_connectUrl enabled:YES];
[self onUnpublished];
[self onStopped];
} |