Пример iOS-приложения для видеозвонков
На скриншоте ниже представлен пример интерфейса до совершения звонка.
Интерфейс приложения такой же, как в примере Phone, за исключением того, что воcпроизводятся два видео
- слева отображается видео с камеры данного пользователя
- справа воспроизводится видео от другой стороны
Работа с кодом примера
Для разбора кода возьмем версию примера PhoneMinVideo, которая доступна для скачивания в сборке 2.5.2.
Класс для основного вида приложения: ViewController (заголовочный файл ViewController.h; файл имплементации ViewController.m).
1. Импорт API. код
#import <FPWCSApi2/FPWCSApi2.h>
2. Подключение к серверу.
FPWCSApi2 createSession, FPWCSApi2Session connect код
В параметрах сессии указываются:
- URL WCS-сервера
- параметры SIP-аккаунта для совершения исходящих и приема входящих звонков
- имя серверного приложения defaultApp
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; ... session = [FPWCSApi2 createSession:options error:&error]; ... [session connect];
3. Исходящий звонок.
FPWCSApi2Session createCall, FPWCSApi2Call call код
При создании звонка в метод createCall передаются параметры:
- имя вызываемого SIP-аккаунта
- вид для отображения локального видеопотока
- вид для отображения видеопотока, получаемого от собеседника
- параметры аудио и видео
- (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 код
[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]; }]; [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]; [self dismissViewControllerAnimated:YES completion:nil]; }]; ... }];
5. Ответ на входящий звонок.
FPWCSApi2Call answer код
alert = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"Incoming call from '%@'", [rCall getCallee]] message:error.localizedDescription preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction* answerButton = [UIAlertAction actionWithTitle:@"Answer" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { [call getLocalConstraints].video = [[FPWCSApi2VideoConstraints alloc] init]; [call setLocalDisplay:_videoView.local]; [call setRemoteDisplay:_videoView.remote]; [call answer]; }]; [alert addAction:answerButton]; UIAlertAction* hangupButton = [UIAlertAction actionWithTitle:@"Hangup" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { [call hangup]; }]; [alert addAction:hangupButton]; [self presentViewController:alert animated:YES completion:nil];
6. Удержание звонка.
FPWCSApi2Call hold, unhold код
- (void)holdButton:(UIButton *)button { [self changeViewState:button enabled:NO]; if ([button.titleLabel.text isEqualToString:@"UNHOLD"]) { if (call) { [call unhold]; [_holdButton setTitle:@"HOLD" forState:UIControlStateNormal]; } } else { if (call) { [call hold]; [_holdButton setTitle:@"UNHOLD" forState:UIControlStateNormal]; } } }
7. Завершение исходящего звонка.
FPWCSApi2Call hangup код
- (void)callButton:(UIButton *)button { [self changeViewState:button enabled:NO]; if ([button.titleLabel.text isEqualToString:@"HANGUP"]) { if ([FPWCSApi2 getSessions].count) { [call hangup]; } else { [self toCallState]; } ... } }
8. Завершение входящего звонка.
FPWCSApi2Call hangup код
UIAlertAction* hangupButton = [UIAlertAction actionWithTitle:@"Hangup" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { [call hangup]; }]; [alert addAction:hangupButton];
9. Закрытие соединения.
FPWCSApi2Session disconnect код
- (void)connectButton:(UIButton *)button { [self changeViewState:button enabled:NO]; if ([button.titleLabel.text isEqualToString:@"DISCONNECT"]) { 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]; } ... } }