Пример iOS-приложения для аудиозвонков
Работа с кодом примера
Для разбора кода возьмем версию примера PhoneMinVideo, которая доступена для скачивания в сборке 2.5.2.
...
1. Импорт API. код
Code Block | ||||
---|---|---|---|---|
| ||||
#import <FPWCSApi2/FPWCSApi2.h> |
...
- URL WCS-сервера
- параметры SIP-аккаунта для совершения исходящих и приема входящих звонков
- имя серверного приложения defaultApp
Code Block | ||||
---|---|---|---|---|
| ||||
FPWCSApi2SessionOptions *options = [[FPWCSApi2SessionOptions alloc] init]; options.urlServer = _connectUrl.text; options.sipRegisterRequired = _sipRegRequired.control.isOn; options.sipLogin = _sipLogin.input.text; options.sipAuthenticationName = _sipAuthName.input.text; options.sipPassword = _sipPassword.input.text; options.sipDomain = _sipDomain.input.text; options.sipOutboundProxy = _sipOutboundProxy.input.text; options.sipPort = [NSNumber numberWithInteger: [_sipPort.input.text integerValue]]; options.appKey = @"defaultApp"; NSError *error; if (!options..sipLogin.length || !options.sipAuthenticationName.length || !options.sipPassword.length || !options.sipDomain.length || !options.sipOutboundProxy.length || options.sipPort.integerValue == 0) { UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"All Sip Credentials is required" message:error.localizedDescription preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction* okButton = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { [self onDisconnected]; }]; [alert addAction:okButton]; [self presentViewController:alert animated:YES completion:nil]; return nil; } session = [FPWCSApi2 createSession:options error:&error]; if (error) { UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"Failed to connect" message:error.localizedDescription preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction* okButton = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { [self onDisconnected]; }]; [alert addAction:okButton]; [self presentViewController:alert animated:YES completion:nil]; return nil; } ... [session connect]; |
3. Исходящий звонок.
FPWCSApi2Session createCall, FPWCSApi2Call call код
При создании звонка в метод createCall передаются параметры:
- имя вызываемого SIP-аккаунта
- вид для отображения локального видеопотока
- вид для отображения видеопотока, получаемого от собеседника
- параметры аудио и видео
Code Block | ||||
---|---|---|---|---|
| ||||
- (FPWCSApi2Call *)call {
FPWCSApi2Session *session = [FPWCSApi2 getSessions][0];
FPWCSApi2CallOptions *options = [[FPWCSApi2CallOptions alloc] init];
options.callee = _callee.input.text;
options.localDisplay = _videoView.local;
options.remoteDisplay = _videoView.remote;
options.localConstraints = [[FPWCSApi2MediaConstraints alloc] initWithAudio:YES video:YES];
options.remoteConstraints = [[FPWCSApi2MediaConstraints alloc] initWithAudio:YES video:YES];
NSError *error;
call = [session createCall:options error:&error];
if (!call) {
UIAlertController * alert = [UIAlertController
alertControllerWithTitle:@"Failed to create call"
message:error.localizedDescription
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* okButton = [UIAlertAction
actionWithTitle:@"Ok"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
[self toCallState];
}];
[alert addAction:okButton];
[self presentViewController:alert animated:YES completion:nil];
return nil;
}
[call on:kFPWCSCallStatusBusy callback:^(FPWCSApi2Call *call){
[self changeCallStatus:call];
[self toCallState];
}];
[call on:kFPWCSCallStatusFailed callback:^(FPWCSApi2Call *call){
[self changeCallStatus:call];
[self toCallState];
}];
[call on:kFPWCSCallStatusRing callback:^(FPWCSApi2Call *call){
[self changeCallStatus:call];
[self toHangupState];
}];
[call on:kFPWCSCallStatusHold callback:^(FPWCSApi2Call *call){
[self changeCallStatus:call];
[self changeViewState:_holdButton enabled:YES];
}];
[call on:kFPWCSCallStatusEstablished callback:^(FPWCSApi2Call *call){
[self changeCallStatus:call];
[self toHangupState];
[self changeViewState:_holdButton enabled:YES];
}];
[call on:kFPWCSCallStatusFinish callback:^(FPWCSApi2Call *call){
[self changeCallStatus:call];
[self toCallState];
}];
[call call];
return call;
} |
4. Получение от сервера события, сигнализирующего о входящем звонке
FPWCSApi2Session onIncomingCallCallback код
Code Block | ||||
---|---|---|---|---|
| ||||
[session onIncomingCallCallback:^(FPWCSApi2Call *rCall) { call = rCall; [call on:kFPWCSCallStatusBusy callback:^(FPWCSApi2Call *call){ [self changeCallStatus:call]; [self toCallState]; }]; [call on:kFPWCSCallStatusFailed callback:^(FPWCSApi2Call *call){ [self changeCallStatus:call]; [self toCallState]; }]; session = [FPWCSApi2 createSession:options error:&error]; ... [session connect]; |
3. Исходящий звонок.
FPWCSApi2Session createCall, FPWCSApi2Call call код
При создании звонка в метод createCall передаются параметры:
- имя вызываемого SIP-аккаунта
- вид для отображения локального видеопотока
- вид для отображения видеопотока, получаемого от собеседника
- параметры аудио и видео
Code Block | ||||
---|---|---|---|---|
| ||||
- (FPWCSApi2Call *)call {
FPWCSApi2Session *session = [FPWCSApi2 getSessions][0];
FPWCSApi2CallOptions *options = [[FPWCSApi2CallOptions alloc] init];
options.callee = _callee.input.text;
options.localDisplay = _videoView.local;
options.remoteDisplay = _videoView.remote;
options.localConstraints = [[FPWCSApi2MediaConstraints alloc] initWithAudio:YES video:YES];
options.remoteConstraints = [[FPWCSApi2MediaConstraints alloc] initWithAudio:YES video:YES];
NSError *error;
call = [session createCall:options error:&error];
...
[call call];
return call;
} |
4. Получение от сервера события, сигнализирующего о входящем звонке
FPWCSApi2Session onIncomingCallCallback код
Code Block | ||||
---|---|---|---|---|
| ||||
[session onIncomingCallCallback:^(FPWCSApi2Call *rCall) { call = rCall; [call on:kFPWCSCallStatusRingkFPWCSCallStatusBusy callback:^(FPWCSApi2Call *call){ [self changeCallStatus:call]; [self toHangupStatetoCallState]; }]; [call on:kFPWCSCallStatusHoldkFPWCSCallStatusFailed callback:^(FPWCSApi2Call *call){ [self changeCallStatus:call]; [self changeViewState:_holdButton enabled:YES[self toCallState]; }]; [call on:kFPWCSCallStatusEstablishedkFPWCSCallStatusRing callback:^(FPWCSApi2Call *call){ [self changeCallStatus:call]; [self toHangupState]; [self changeViewState:_holdButton enabled:YES]; }]; [call on:kFPWCSCallStatusFinishkFPWCSCallStatusHold callback:^(FPWCSApi2Call *call){ [self changeCallStatus:call]; [self toCallState]; [self dismissViewControllerAnimated:YES completion:nil]; }changeViewState:_holdButton enabled:YES]; ... }]; |
5. Ответ на входящий звонок.
FPWCSApi2Call answer код
Code Block | ||||
---|---|---|---|---|
| ||||
alert = [UIAlertController [call on:kFPWCSCallStatusEstablished callback:^(FPWCSApi2Call *call){ [self changeCallStatus:call]; alertControllerWithTitle:[NSString stringWithFormat:@"Incoming call from '%@'", [rCall getCallee]][self toHangupState]; [self changeViewState:_holdButton enabled:YES]; }]; [call on:kFPWCSCallStatusFinish message:error.localizedDescriptioncallback:^(FPWCSApi2Call *call){ [self changeCallStatus:call]; [self toCallState]; [self dismissViewControllerAnimated:YES preferredStylecompletion:UIAlertControllerStyleAlertnil]; }]; UIAlertAction* answerButton... }]; |
5. Ответ на входящий звонок.
FPWCSApi2Call answer код
Code Block | ||||
---|---|---|---|---|
| ||||
alert = [UIAlertActionUIAlertController actionWithTitlealertControllerWithTitle:[NSString stringWithFormat:@"Answer" Incoming call from '%@'", [rCall getCallee]] stylemessage:UIAlertActionStyleDefaulterror.localizedDescription handler:^(UIAlertAction * action) {preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction* answerButton = [UIAlertAction [call getLocalConstraints].video = [[FPWCSApi2VideoConstraints alloc] init]; actionWithTitle:@"Answer" [call setLocalDisplay:_videoView.local]; style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { [call setRemoteDisplay:_videoView.remote]; [call getLocalConstraints].video = [call answer[[FPWCSApi2VideoConstraints alloc] init]; }]; [alertcall addAction:answerButton]; UIAlertAction* hangupButton = [UIAlertActionsetLocalDisplay:_videoView.local]; actionWithTitle:@"Hangup" [call setRemoteDisplay:_videoView.remote]; style:UIAlertActionStyleDefault [call answer]; handler:^(UIAlertAction * action) { }]; [alert addAction:answerButton]; UIAlertAction* hangupButton = [UIAlertAction [call hangup]; actionWithTitle:@"Hangup" }]; [alert addAction:hangupButton]; [self presentViewController:alert animated:YES completion:nil]; |
6. Удержание звонка.
FPWCSApi2Call hold, unhold код
Code Block | ||||
---|---|---|---|---|
| ||||
- (void)holdButton:(UIButton *)button { [self changeViewState:button enabledstyle:NO];UIAlertActionStyleDefault if ([button.titleLabel.text isEqualToString:@"UNHOLD"]) { if (call) { [call unhold]; handler:^(UIAlertAction * action) { [_holdButton setTitle:@"HOLD" forState:UIControlStateNormal]; } } else { if ([call) {hangup]; [call hold]; [_holdButton setTitle:@"UNHOLD" forState:UIControlStateNormal }]; } } } |
...
[alert addAction:hangupButton];
[self presentViewController:alert animated:YES completion:nil];
|
6. Удержание звонка.
FPWCSApi2Call hangup hold, unhold код
Code Block | ||||
---|---|---|---|---|
| ||||
- (void)callButtonholdButton:(UIButton *)button { [self changeViewState:button enabled:NO]; if ([button.titleLabel.text isEqualToString:@"HANGUPUNHOLD"]) { if ([FPWCSApi2 getSessions].countcall) { [call hangupunhold]; } else { [_holdButton [self toCallStatesetTitle:@"HOLD" forState:UIControlStateNormal]; } } else { if ([FPWCSApi2 getSessions].countcall) { [selfcall callhold]; } else { [_holdButton [self toCallStatesetTitle:@"UNHOLD" forState:UIControlStateNormal]; } } } |
87. Завершение входящего исходящего звонка.
FPWCSApi2Call hangup код
Code Block | ||||
---|---|---|---|---|
| ||||
UIAlertAction* hangupButton = [UIAlertAction - (void)callButton:(UIButton *)button { [self changeViewState:button enabled:NO]; if ([button.titleLabel.text isEqualToString:@"HANGUP"]) { if ([FPWCSApi2 actionWithTitle:@"Hangup"getSessions].count) { [call hangup]; } else { style:UIAlertActionStyleDefault [self toCallState]; } ... } } |
8. Завершение входящего звонка.
FPWCSApi2Call hangup код
Code Block | ||||
---|---|---|---|---|
| ||||
UIAlertAction* hangupButton handler:^(UIAlertAction * action) { = [UIAlertAction actionWithTitle:@"Hangup" [call hangup]; style:UIAlertActionStyleDefault }]; [alert addAction:hangupButton]; |
9. Закрытие соединения.
FPWCSApi2Session disconnect код
Code Block | ||||
---|---|---|---|---|
| ||||
- (void)connectButton:(UIButton *)button { [self changeViewState:button enabled:NO]; if ([button.titleLabel.text isEqualToString:@"DISCONNECT"]handler:^(UIAlertAction * action) { if ([FPWCSApi2 getSessions].count) { FPWCSApi2Session *session = [FPWCSApi2 getSessions][0call hangup]; NSLog(@"Disconnect session with server %@", [session getServerUrl]); [session disconnect}]; } else { NSLog(@"Nothing to disconnect"); [alert addAction:hangupButton]; |
9. Закрытие соединения.
FPWCSApi2Session disconnect код
Code Block | ||||
---|---|---|---|---|
| ||||
- (void)connectButton:(UIButton *)button { [self onDisconnected changeViewState:button enabled:NO]; if ([button.titleLabel.text }isEqualToString:@"DISCONNECT"]) { } else { if ([FPWCSApi2 getSessions].count) { //todo check url is not empty FPWCSApi2Session *session = [FPWCSApi2 [self changeViewState:_connectUrl enabled:NOgetSessions][0]; [self changeViewState:_sipLogin.input enabled:NO]; [self changeViewState:_sipAuthName.input enabled:NO] NSLog(@"Disconnect session with server %@", [session getServerUrl]); [self changeViewState:_sipPassword.input enabled:NOsession disconnect]; } [self changeViewState:_sipDomain.input enabled:NO]; else { [self changeViewState:_sipOutboundProxy.input enabled:NO]; NSLog(@"Nothing to disconnect"); [self changeViewState:_sipRegRequired.control enabled:NOonDisconnected]; [self changeViewState:_sipPort.input enabled:NO];} [self connect];... } } |